Почему «эхо» намного быстрее, чем «чаевые»?

Я пытаюсь обновить временную метку до текущего времени на всех 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

Почему эхо намного быстрее, чем касание здесь?

115 голосов | спросил Casey Patton 9 AMpWed, 09 Apr 2014 07:14:41 +040014Wednesday 2014, 07:14:41

3 ответа


161

В bash touch является внешним двоичным кодом, но echo является встроенная оболочка :

$ type echo
echo is a shell builtin
$ type touch
touch is /usr/bin/touch

Так как touch является внешним двоичным кодом, и вы вызываете touch один раз для каждого файла, оболочка должна создать 300 000 экземпляров touch, что принимает долгое время.

echo, однако, является встроенной оболочкой, а выполнение встроенных команд оболочки вообще не требует разметки. Вместо этого текущая оболочка выполняет все операции и внешние процессы не создаются; это причина, по которой это происходит намного быстрее.

Вот два профиля операций оболочки. Вы можете видеть, что много времени тратится на клонирование новых процессов при использовании touch. Использование /bin/echo вместо встроенной оболочки должно показать гораздо более сопоставимый результат.


Использование touch

$ strace -c -- bash -c 'for file in a{1..10000}; do touch "$file"; done'
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 56.20    0.030925           2     20000     10000 wait4
 38.12    0.020972           2     10000           clone
  4.67    0.002569           0     80006           rt_sigprocmask
  0.71    0.000388           0     20008           rt_sigaction
  0.27    0.000150           0     10000           rt_sigreturn
[...]

Использование эха

$ strace -c -- bash -c 'for file in b{1..10000}; do echo >> "$file"; done'
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 34.32    0.000685           0     50000           fcntl
 22.14    0.000442           0     10000           write
 19.59    0.000391           0     10011           open
 14.58    0.000291           0     20000           dup2
  8.37    0.000167           0     20013           close
[...]
ответил Chris Down 9 AMpWed, 09 Apr 2014 08:24:17 +040024Wednesday 2014, 08:24:17
71

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

Однако обратите внимание, что самый быстрый способ добиться этого эффекта по-прежнему использовать touch, но вместо того, чтобы запускать программу один раз для каждого файла, можно использовать -exec с find, чтобы убедиться, что он выполняется только несколько раз. Этот подход обычно будет более быстрым, поскольку он позволяет избежать накладных расходов, связанных с циклом оболочки:

find . -name "*.xml" -exec touch {} +

Использование + (в отличие от \;) с помощью find ... -exec запускает команду только один раз, если это возможно, с каждой файл в качестве аргумента. Если список аргументов очень длинный (как в случае с 300 000 файлов), будет выполняться несколько прогонов с списком аргументов, длина которого близка к пределу (ARG_MAX для большинства систем).

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

ответил Graeme 9 PMpWed, 09 Apr 2014 15:36:09 +040036Wednesday 2014, 15:36:09
29

echo - это встроенная оболочка. С другой стороны, touch является внешним двоичным кодом.

$ type echo
echo is a shell builtin
$ type touch
touch is hashed (/usr/bin/touch)

Встроенные оболочки намного быстрее, так как нет никаких накладных расходов на загрузку программы, т. е. нет fork /exec. Таким образом, вы будете наблюдать значительную разницу во времени, когда большое количество раз выполняете встроенную внешнюю команду.

Это причина, по которой утилиты, такие как time, доступны как встроенные оболочки.

Вы можете получить полный список встроенных оболочек, говоря:

enable -p

Как упоминалось выше, использование утилиты в отличие от builtin приводит к значительному снижению производительности. Ниже приведены статистические данные о времени, затрачиваемом на создание ~ 9000 файлов с помощью встроенного echo и утилиты echo:

# Using builtin
$ time bash -c 'for i in {1000..9999}; do echo > $i; done'

real    0m0.283s
user    0m0.100s
sys 0m0.184s

# Using utility /bin/echo
$ time bash -c 'for i in {1000..9999}; do /bin/echo > $i; done'

real    0m8.683s
user    0m0.360s
sys 0m1.428s
ответил devnull 9 AMpWed, 09 Apr 2014 08:24:36 +040024Wednesday 2014, 08:24:36

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

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132