Я пытаюсь обновить метку времени до текущего времени для всех файлов XML в моем каталоге (рекурсивно). Я использую Mac OSX 10.8.5.
Приблизительно для 300 000 файлов следующая echo
команда занимает 10 секунд :
for file in `find . -name "*.xml"`; do echo >> $file; done
Однако следующая touch
команда занимает 10 минут ! :
for file in `find . -name "*.xml"`; do touch $file; done
Почему эхо намного быстрее, чем прикосновение?
echo >> $file
он добавит новую строку$file
и, таким образом , изменит ее. Я предполагаю, что это будет то же самое для OS / X. Если вы не хотите этого, используйтеecho -n >> $file
.touch `find . -name "*.xml"`
будет даже быстрее, чем оба из вышеперечисленного?>>$file
touch
вообще так много раз вызывать ?find . -name '*.xml' -print0 | xargs -0 touch
вызываетtouch
намного меньше раз (возможно, только один раз). Работает на Linux, должен работать на OS X.Ответы:
В bash
touch
это внешний бинарный файл, ноecho
это встроенная оболочка :Поскольку
touch
это внешний двоичный файл, и вы вызываете егоtouch
один раз для файла, оболочка должна создать 300 000 экземпляровtouch
, что занимает много времени.echo
однако это встроенная оболочка, и выполнение встроенных оболочек вообще не требует разветвления. Вместо этого текущая оболочка выполняет все операции, и внешние процессы не создаются; это причина, почему это намного быстрее.Вот два профиля операций оболочки. Вы можете видеть, что при использовании вы тратите много времени на клонирование новых процессов
touch
. Использование/bin/echo
вместо встроенной оболочки должно показывать гораздо более сопоставимый результат.Используя сенсорный
Используя эхо
источник
Как и другие ответили, используя
echo
будет быстрее , чем ,touch
какecho
это команда , которая обычно (хотя и не обязательно быть) , встроенные в оболочку. Его использование избавляет от накладных расходов ядра, связанных с запуском запуска нового процесса для каждого файла, который вы получаетеtouch
.Однако обратите внимание, что самым быстрым способом достижения этого эффекта по-прежнему является использование
touch
, но вместо того, чтобы запускать программу один раз для каждого файла, можно использовать-exec
опцию с,find
чтобы обеспечить запуск только несколько раз. Этот подход обычно будет быстрее, поскольку он позволяет избежать накладных расходов, связанных с циклом оболочки:Использование
+
(в отличие от\;
) сfind ... -exec
запускает команду только один раз, если это возможно, с каждым файлом в качестве аргумента. Если список аргументов очень длинный (как в случае с 300 000 файлов), будет выполнено несколько запусков со списком аргументов, длина которого близка к пределу (ARG_MAX
в большинстве систем).Другое преимущество этого подхода состоит в том, что он ведет себя надежно с именами файлов, содержащими все пробельные символы, что не имеет место в исходном цикле.
источник
+1
для указания+
аргумента поиска . Я думаю, что многие люди не знают об этом (я не был).find
имеют+
аргумент. Вы можете получить аналогичный эффект по трубопроводуxargs
.+
часть требуется POSIX, поэтому должна быть переносимой.-print0
нет.find
есть доступная опция, но только рассматривает это как;
под поверхностью.echo
это встроенная оболочка С другой стороны,touch
это внешний двоичный файл.Эти команды гораздо быстрее , так как нет никаких накладных расходов участвуют в загрузке программы, т.е. нет
fork
/exec
участия. Таким образом, вы заметите значительную разницу во времени при выполнении встроенной или внешней команды большое количество раз.Это причина того, что подобные утилиты
time
доступны в виде встроенных командных оболочек.Вы можете получить полный список встроенных команд оболочки, сказав:
Как уже упоминалось выше, использование утилиты, а не встроенной, приводит к значительному снижению производительности. Ниже приведена статистика времени, затраченного на создание ~ 9000 файлов с использованием встроенной программы
echo
и утилитыecho
:источник
echo
большинстве систем есть бинарный файл (для меня это/bin/echo
), поэтому вы можете повторить тесты синхронизации, используя его вместо встроенного