Самый быстрый 'uniq' инструмент в Linux

Я также добавил бы, что, чтобы успешно найти (и удалить) точные дубликаты файла, необходимо сравнить файлы хешем:

#!/bin/sh -eu
find "${1:-.}" -type f ! -empty -print0 | xargs -0 md5 -r | \
    awk '$1 in a{sub("^.{33}","");printf "%s\0",$0}a[$1]+=1{}' | \
    xargs -0 rm -v --

Сохраните это как deldupes.sh и выполненный это дающий dirname как 1-й параметр (иначе $PWD использовался бы).

Протестированный на OS X, работы долгое время whitespaced имена файлов.

8
21.09.2016, 14:08
3 ответа
[118350] Рассмотрим, как работает каждое решение.[12155]uniq[119123] Это требует, чтобы файл уже был отсортирован. Если нет, то сначала необходимо пропустить его через [119124]сортировку[119125], что означает, что [119126]сортировка[119127] должна прочитать весь файл в память, переупорядочить его ([119128]O(n log n)[119129]), а затем записать его в трубку. Работа [119130]uniq[119131] очень дешева, так как ей приходится сравнивать только соседние строки своего входа.[12156]sort -u[119133] Это объединяет работу [119134]sort | uniq[119135]. Это должно собрать все уникальные входные данные в память, как это делает скрипт [119136]awk[119137], но он также тратит время на их сортировку перед производством вывода. Это [119138]O(n log n)[119139], хотя в данном случае [119140]n[119141] - это количество уникальных элементов, а не всех входов. Так что это лучше, чем труба. [12157]sed[119143] я не уверен, почему Вы перечислили это, так как я вообще не могу придумать хороший способ сделать это с [119144]sed[119145]. Может быть, если вы сначала отсортируете его и подключите к сценарию [119146]sed[119147], есть способ сравнить соседние строки. Так что [119148]sed[119149] будет просто делать то, что делает [119150]uniq[119151], и [119152]uniq[119153], вероятно, делает это максимально эффективно.[12158]awk[119155] Это, вероятно, лучше всего, потому что он делает только минимально необходимый объем работы. Так как он считывает каждую строку, он делает эффективный хэш-поиск, чтобы увидеть, не находится ли строка уже в памяти, и сохраняет только уникальные строки в виде хэш-клавиш, а счетчик в виде значения. (Если раньше строки не было, условие будет истинным, поэтому строка будет выведена на печать. Иначе не будет.) При этом используется время [119156]O(n)[119157] и память [119158]O(uniq n)[119159].[12159]Каждый метод будет использовать значительный объем памяти, либо для сортировки входа, либо для отслеживания того, какие входы видели, чтобы удалить дубликаты.[118355].
16
27.01.2020, 20:09

Я обнаружил, что сортировка - это самый быстрый инструмент uniq, как показано здесь -> Самый быстрый способ удалить дубликаты в большом списке слов?

0
27.01.2020, 20:09

Я просто хотел отметить, что gnu uniqкажется ужасно медленным, даже в отсортированном списке.

Я только что попытался получить список префиксов каталогов из списка отсортированных имен файлов:

$ pv all_files | cut -d '/' -f 1,2,3,4 | uniq > all_prefixes

36.7GiB 0:07:41 [81.4MiB/s]

$ pv all_files | cut -d '/' -f 1,2,3,4 | sort -u > all_prefixes2

36.7GiB 0:03:14 [ 193MiB/s]

$ pv all_files  | cut -d '/' -f 1,2,3,4 | awk '!x[$0]++' > all_prefixes3                                        
36.7GiB 0:02:18 [ 270MiB/s] 

sort -u кажется в два раза быстрее, чем uniq, и это при чтении sort со стандартного ввода и записи на стандартный вывод, поэтому я пока не вижу параллелизма. Я понятия не имею, почему uniq должен быть намного медленнее, чем sort, ведь ему не нужно сортировать список...

Вывод этой команды очень мал (много дубликатов ), всего 264kb и сортировка завершается сразу после выполнения pv.

Те же скорости остаются, если вы измените порядок команд, мой поток здесь ограничен процессорным временем, а не доступом к диску и кешем (У меня только 8 ГБ ОЗУ, и мой своп не используется)

Я запускаю это на машине с Fedora 31 с помощью gnu coreutils sort и uniq и gnu awk; установлен локаль en _US.UTF -8

ОБНОВЛЕНИЕ , поскольку это меня немного заинтриговало, я провел еще несколько тестов, давайте уберем отрезанную часть,и убедитесь, что файл хорошо отсортирован

cat all_files | cut -d '/' -f 1,2,3,4 | sort -T. > test

Это занимает 8,4 минуты. test теперь весит 7,9 ГБ

Давайте запустим эти инструменты в файле, а не в конвейере, это позволит этим инструментам выполнить дополнительную оптимизацию, например, сортировка будет многопоточной. а также с более быстрого ssd.

Вы можете не заметить, что эта сортировка также занимает много памяти, так как она делает хитрые трюки с временными файлами в /tmp, которые могут быть tmpfs и будут находиться в вашей оперативной памяти. (Попробуйте отсортировать файл больше, чем /tmp, вы столкнетесь с проблемами свободного места, поэтому мне нужен -T. флаг в приведенной выше команде)

$ time sort -u test > /dev/null
339.24user 3.54system 1:28.87elapsed 385%CPU (0avgtext+0avgdata 2365856maxresident)k
9555544inputs+0outputs (0major+591298minor)pagefaults 0swaps

$ time awk '!x[$0]++' test > /dev/null                                                                                                                             
51.15user 1.55system 0:52.94elapsed 99%CPU (0avgtext+0avgdata 10976maxresident)k
0inputs+0outputs (0major+1923minor)pagefaults 0swaps

$ time uniq test > /dev/null                                                                                                                                  
421.89user 2.76system 7:06.63elapsed 99%CPU (0avgtext+0avgdata 1980maxresident)k
52712inputs+0outputs (0major+79minor)pagefaults 0swaps

Похоже, ваше решение на awk самое быстрое из этих трех и на самом деле использует наименьшее количество памяти

обновление2 и теперь с более простой локалью

$ export LC_ALL=c
$ time sort -u test > /dev/null                                                                                                                                             1.2m ? Tue Apr 21 17:09:22 2020
119.18user 3.64system 0:38.24elapsed 321%CPU (0avgtext+0avgdata 2013472maxresident)k

$ time awk '!x[$0]++' test > /dev/null                                                                                                                                1161ms ? Tue Apr 21 17:07:31 2020
67.23user 2.50system 1:10.16elapsed 99%CPU (0avgtext+0avgdata 10480maxresident)k
7187520inputs+0outputs (0major+1912minor)pagefaults 0swaps

$ time uniq test > /dev/null                                                                                                                                               
22.05user 2.02system 0:24.24elapsed 99%CPU (0avgtext+0avgdata 1488maxresident)k
2959648inputs+0outputs (1major+72minor)pagefaults 0swaps

На этот раз uniq выигрывает гонку ... Как намекает Стефан Шазеля в комментариях, установка языкового стандарта C делает сортировку и уникальность намного быстрее!

1
20.04.2020, 14:19

Теги

Похожие вопросы