Почему printf удара быстрее, чем/usr/bin/printf?

Не уверенный, если это не должно быть перемещено в askubuntu, но просто использовать тот же подход в качестве в упомянутом потоке. Выполненный dpkg/dpkg-query, чтобы получить дамп всех данных и использовать стандартный Python, анализирующий механизмы для извлечения релевантной информации.

Конечно, так как Вы уже разветвляетесь, можно сделать все текстовое искажение в самом ударе.

С другой стороны, найдите файл состояния, который содержит версии, если существует кто-либо ("Dir:: И т.д.:: Состояние"?). Этот подход был бы самым чистым.

5
24.02.2017, 18:01
3 ответа

Автономный printf

Часть "расхода" в вызове процесса - то, что несколько вещей должны произойти, которые являются интенсивно использующими ресурсы.

  1. Исполняемый файл должен быть загружен из диска, это подвергается замедлению, так как жесткий диск имеет быть быть полученным доступ для загрузки двоичного блоба из диска, который исполняемый файл хранится как.
  2. Исполняемый файл обычно создается, пользуясь динамическими библиотеками, таким образом, некоторые вторичные файлы к исполняемому файлу должны будут также быть загружены, (т.е. больше двоичных данных блоба, считанных из жесткого диска).
  3. Операционная система наверху. Каждый процесс, который Вы вызываете, подвергается наверху в форме идентификатора процесса, имеющего необходимость быть созданным для него. Пространство в памяти будет также иметь быть вырезанным к оба, содержат двоичные данные, загружаемые из жесткого диска на шагах 1 и 2, а также нескольких структур, имеющих необходимость быть заполненными для хранения вещей, таких как среда процессов (переменные среды и т.д.)

выборка strace /usr/bin/printf

    $ strace /usr/bin/printf "%s\n" "hello world"
    *execve("/usr/bin/printf", ["/usr/bin/printf", "%s\\n", "hello world"], [/* 91 vars */]) = 0
    brk(0)                                  = 0xe91000
    mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fd155a6b000
    access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
    open("/etc/ld.so.cache", O_RDONLY)      = 3
    fstat(3, {st_mode=S_IFREG|0644, st_size=242452, ...}) = 0
    mmap(NULL, 242452, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fd155a2f000
    close(3)                                = 0
    open("/lib64/libc.so.6", O_RDONLY)      = 3
    read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0p\357!\3474\0\0\0"..., 832) = 832
    fstat(3, {st_mode=S_IFREG|0755, st_size=1956608, ...}) = 0
    mmap(0x34e7200000, 3781816, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x34e7200000
    mprotect(0x34e7391000, 2097152, PROT_NONE) = 0
    mmap(0x34e7591000, 20480, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x191000) = 0x34e7591000
    mmap(0x34e7596000, 21688, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x34e7596000
    close(3)                                = 0
    mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fd155a2e000
    mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fd155a2c000
    arch_prctl(ARCH_SET_FS, 0x7fd155a2c720) = 0
    mprotect(0x34e7591000, 16384, PROT_READ) = 0
    mprotect(0x34e701e000, 4096, PROT_READ) = 0
    munmap(0x7fd155a2f000, 242452)          = 0
    brk(0)                                  = 0xe91000
    brk(0xeb2000)                           = 0xeb2000
    brk(0)                                  = 0xeb2000
    open("/usr/lib/locale/locale-archive", O_RDONLY) = 3
    fstat(3, {st_mode=S_IFREG|0644, st_size=99158752, ...}) = 0
    mmap(NULL, 99158752, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fd14fb9b000
    close(3)                                = 0
    fstat(1, {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0
    mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fd155a6a000
    write(1, "hello world\n", 12hello world
    )           = 12
    close(1)                                = 0
    munmap(0x7fd155a6a000, 4096)            = 0
    close(2)                                = 0
    exit_group(0)                           = ?*

При просмотре вышеупомянутого можно получить смысл дополнительных ресурсов это /usr/bin/printf должен подвергнуться из-за него являющийся автономным исполняемым файлом.

Встроенный printf

С созданной версией printf все библиотеки, что это зависит от, а также его двоичный блоб, были уже загружены в память, когда Bash был вызван. Таким образом, ничего подобного не должен быть понесен снова.

Эффективно при вызове встроенных "команд" к Bash Вы действительно делаете, какие суммы к вызову функции, так как все было уже загружено.

Аналогия

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

Анатомия управления процессами Linux

Существует довольно хорошая статья о IBM Developerworks, которая ломает различные аспекты того, как процессы Linux создаются и уничтожаются наряду с различными библиотеками C, вовлеченными в процесс. Статья является titled:Anatomy управления процессами Linux - Создание, управление, планирование и разрушение. Это также доступно как PDF.

6
27.01.2020, 20:33
  • 1
    Не Был бы в цикле только самое первое printf вызов должен считать что-то из диска, и последующие прибыли бы из кэша файловой системы? Для одноразового, что я согласился бы, что это может быть источник замедления, но в этом случае я подозревал бы все другие причины перед той. –  Joey 31.01.2018, 09:36

Выполнение внешней команды /usr/bin/printf приводит к созданию процесса, которое не делает встроенная оболочка. Так, для цикла 3 000, 3 000 процессов, созданных, и следовательно медленнее.

Можно проверить это путем выполнения их вне цикла:

4
27.01.2020, 20:33
  • 1
    Достаточно ярмарка, я просто не ожидал бы, что создание процесса будет настолько дорогим, который является огромной разницей. –  terdon♦ 27.09.2013, 08:34
  • 2
    @terdon Вы также говорите, что исполняемый файл является программой C и что это должно быть быстро. Оболочка также записана в C, и реализация может быть как быстро (или могло даже быть то же). –  Matteo 27.09.2013, 08:38
  • 3
    @Matteo, но оболочка делает все виды других вещей, я ожидал бы, что автономная, специализированная программа будет быстрее. Я разъяснюсь. –  terdon♦ 27.09.2013, 08:43
  • 4
    @Guru, посмотрите обновленный вопрос. –  terdon♦ 27.09.2013, 08:44
  • 5
    "оболочка делает все виды других вещей"-> нет, оболочка является единственным потоковым процессом. Это делает только одну вещь за один раз... кроме тех случаев, когда это разветвляется (который на самом деле делает это двумя оболочками). "Я просто не ожидал бы, что создание процесса будет настолько дорогим"-> я предположу, что создание процесса является почти столь дорогим системным вызовом, как можно найти. Каждый из тех является a fork(). Все новое адресное пространство должно быть создано и т.д. –  goldilocks 27.09.2013, 09:31

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

$ time /usr/bin/printf %2000000000s > /dev/null
/usr/bin/printf %2000000000s > /dev/null  13.72s user 1.42s system 99% cpu 15.238 total

$ time busybox printf %2000000000s > /dev/null
busybox printf %2000000000s > /dev/null  1.50s user 0.49s system 95% cpu 2.078 total


$ time bash -c 'printf %2000000000s' > /dev/null
bash -c 'printf %2000000000s' > /dev/null  4.59s user 3.35s system 84% cpu 9.375 total

$ time zsh -c 'printf %2000000000s' > /dev/null
zsh -c 'printf %2000000000s' > /dev/null  1.48s user 0.24s system 81% cpu 2.115 total

$ time ksh -c 'printf %2000000000s' > /dev/null
ksh -c 'printf %2000000000s' > /dev/null  0.48s user 0.00s system 88% cpu 0.543 total

$ time mksh -c 'printf %2000000000s' > /dev/null
mksh -c 'printf %2000000000s' > /dev/null  13.59s user 1.57s system 99% cpu 15.262 total

$ time ash -c 'printf %2000000000s' > /dev/null
ash -c 'printf %2000000000s' > /dev/null  13.74s user 1.42s system 99% cpu 15.214 total

$ time yash -c 'printf %2000000000s' > /dev/null
yash -c 'printf %2000000000s' > /dev/null  13.73s user 1.40s system 99% cpu 15.186 total

Вы видите что, по крайней мере, в том отношении, GNU printf не был оптимизирован для производительности. Нет большого количества точки, оптимизируя команду как printf так или иначе, потому что для 99,999% использований, потраченное выполнение времени действия будет омраченным временем выполнения так или иначе. Это имеет намного больше смысла оптимизировать команды как grep или sed это может потенциально обработать гигабайты данных в одном выполнении.

4
27.01.2020, 20:33
  • 1
    Одно примечание: mksh официально не включает printf поскольку встроенные, но более старые сборки Debian его сделали (потому что udev специалист по обслуживанию настоял на непортативных предположениях), но это было быстрым неоптимизированным неполным взломом. А-ч –  mirabilos 27.02.2014, 16:08

Теги

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