Ускорение сравнения файлов (с `cmp`) на Cygwin? - PullRequest
6 голосов
/ 24 января 2012

Я написал сценарий bash для Cygwin, который похож на rsync, хотя и достаточно отличается, так что я считаю, что на самом деле не могу использовать rsync для того, что мне нужно.Он перебирает около тысячи пар файлов в соответствующих каталогах, сравнивая их с cmp.

К сожалению, кажется, что это работает ужасно медленно - примерно в десять (Edit: фактически 25!) Раз дольшетребуется сгенерировать один из наборов файлов с помощью программы на Python.

Правильно ли я считаю, что это удивительно медленно?Есть ли какие-нибудь простые альтернативы, которые бы работали быстрее?

(Чтобы немного рассказать о моем сценарии использования: я автоматически генерирую кучу файлов .c во временном каталоге, и когда я их заново генерирую,Я хотел бы скопировать только те, которые изменились в фактический исходный каталог, оставив неизмененными (без их старых времен создания), так что make будет знать, что это не нужноперекомпилируйте их. Однако не все сгенерированные файлы являются .c файлами, поэтому мне нужно делать двоичные сравнения, а не текстовые сравнения.)

Ответы [ 2 ]

3 голосов
/ 24 января 2012

Может быть, вам стоит использовать Python для выполнения некоторых или даже всех сравнительных работ?

Одним из улучшений будет использование только cmp, если размеры файлов одинаковы; если они разные, файл явно изменился. Вместо запуска cmp вы можете подумать о генерации хеша для каждого файла, используя MD5 или SHA1 или SHA-256 или что-то еще, что вам нравится (используя модули или расширения Python, если это правильный термин). Если вы не думаете, что будете иметь дело со злым умыслом, то MD5, вероятно, достаточно для выявления различий.

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

Да, звучит так, будто это занимает слишком много времени. Но проблема заключается в том, что нужно запустить 1000 копий cmp, а также другую обработку. Как в приведенных выше предложениях Python, так и в сценарии оболочки есть то, что они избегают запуска программы 1000 раз; они пытаются минимизировать количество выполняемых программ. Полагаю, это сокращение числа выполняемых процессов даст вам неплохой удар.


Если вы можете хранить хэши в «текущем наборе файлов» и просто генерировать новые хэши для нового набора файлов, а затем сравнивать их, у вас все получится. Ясно, что если файл, содержащий «старые хэши» (текущий набор файлов), отсутствует, вам придется восстановить его из существующих файлов. Это немного конкретизирует информацию в комментариях.

Еще одна возможность: можете ли вы отслеживать изменения в данных, которые вы используете для генерации этих файлов, и использовать их, чтобы сообщать вам, какие файлы будут изменены (или, по крайней мере, ограничить набор файлов, которые могли измениться и что поэтому нужно сравнивать, так как ваши комментарии показывают, что большинство файлов всегда одинаковы).

1 голос
/ 24 января 2012

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

Краткий ответ: добавьте --silent к вашему cmp вызову, если его еще нет.

Возможно, вы сможете ускорить версию Python, выполнив некоторые проверки размера файла перед проверкой данных.

Во-первых, быстрый и хакерский метод bash(1), который может быть намного проще, если вы можете перейти на один каталог build: используйте тест bash -N:

$ echo foo > file
$ if [ -N file ] ; then echo newer than last read ; else echo older than last read ; fi
newer than last read
$ cat file
foo
$ if [ -N file ] ; then echo newer than last read ; else echo older than last read ; fi
older than last read
$ echo blort > file # regenerate the file here
$ if [ -N file ] ; then echo newer than last read ; else echo older than last read ; fi
newer than last read
$ 

Конечно, если некоторое подмножество файлов зависит от некоторого другого подмножества сгенерированных файлов, этот подход не будет работать вообще. (Это может быть достаточной причиной, чтобы избежать этой техники; решать вам.)

В вашей программе на Python вы также можете проверить файл размеры , используя os.stat(), чтобы определить, следует ли вам вызывать процедуру сравнения; если файлы имеют разные размеры, вам не важно, какие байты были изменены, поэтому вы можете пропустить чтение обоих файлов. (Это было бы трудно сделать в bash(1) - я не знаю ни одного механизма, чтобы получить размер файла в bash(1) без выполнения другой программы, которая отвергает весь смысл этой проверки.)

Программа cmp выполнит внутреннее сравнение размеров, если вы используете --silent флаг и , оба файла являются обычными файлами и , оба файла расположены в одном месте , (Это устанавливается с помощью флага --ignore-initial.) Если вы не используете --silent, добавьте его и посмотрите, в чем разница.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...