Я хочу time
команду, которая состоит из двух отдельных команд с одним выводом трубопровода к другому. Например, рассмотрим два сценария ниже:
$ cat foo.sh
#!/bin/sh
sleep 4
$ cat bar.sh
#!/bin/sh
sleep 2
Теперь, как я могу time
сообщить о потраченном времени foo.sh | bar.sh
(и да, я знаю, что канал здесь не имеет смысла, но это всего лишь пример)? Это работает, как и ожидалось, если я запускаю их последовательно в подоболочке без трубопровода:
$ time ( foo.sh; bar.sh )
real 0m6.020s
user 0m0.010s
sys 0m0.003s
Но я не могу заставить его работать при обвязке:
$ time ( foo.sh | bar.sh )
real 0m4.009s
user 0m0.007s
sys 0m0.003s
$ time ( { foo.sh | bar.sh; } )
real 0m4.008s
user 0m0.007s
sys 0m0.000s
$ time sh -c "foo.sh | bar.sh "
real 0m4.006s
user 0m0.000s
sys 0m0.000s
Я прочитал аналогичный вопрос ( Как запустить время на нескольких командах И записать вывод времени в файл? ), А также попробовал автономный time
исполняемый файл:
$ /usr/bin/time -p sh -c "foo.sh | bar.sh"
real 4.01
user 0.00
sys 0.00
Это даже не работает, если я создаю третий скрипт, который запускает только канал:
$ cat baz.sh
#!/bin/sh
foo.sh | bar.sh
И тогда время, которое:
$ time baz.sh
real 0m4.009s
user 0m0.003s
sys 0m0.000s
Интересно, что он не выглядит так, как будто time
завершается, как только первая команда выполнена. Если я изменю bar.sh
на:
#!/bin/sh
sleep 2
seq 1 5
И time
опять же, я ожидал, что time
вывод будет напечатан раньше, seq
но это не так:
$ time ( { foo.sh | bar.sh; } )
1
2
3
4
5
real 0m4.005s
user 0m0.003s
sys 0m0.000s
Похоже time
, не считается время, которое потребовалось для выполнения, bar.sh
несмотря на ожидание его завершения перед печатью своего отчета 1 .
Все тесты выполнялись в системе Arch и использовали выпуск bash 4.4.12 (1). Я могу использовать bash только для проекта, частью которого он является, так что даже если zsh
или какая-то другая мощная оболочка сможет обойти его, это не будет для меня жизнеспособным решением.
Итак, как я могу получить время, которое потребовалось для запуска набора конвейерных команд? И, хотя мы на это, почему это не работает? Похоже, что time
сразу выходит, как только первая команда закончена. Зачем?
Я знаю, что могу получить индивидуальные времена с чем-то вроде этого:
( time foo.sh ) 2>foo.time | ( time bar.sh ) 2> bar.time
Но я все еще хотел бы знать, возможно ли рассчитать все это как одну операцию.
1 Похоже, что это не проблема с буфером, я попытался запустить сценарии с unbuffered
и, stdbuf -i0 -o0 -e0
и числа все еще печатались до time
вывода.
Ответы:
Он будет работать.
Различные части конвейера выполняются одновременно. Единственное, что синхронизирует / сериализует процессы в конвейере, - это IO, то есть один процесс записывает следующий процесс в конвейере, а следующий процесс читает то, что пишет первый. Кроме того, они выполняются независимо друг от друга.
Поскольку между процессами в вашем конвейере не происходит чтение или запись, время выполнения конвейера - это время самого длинного
sleep
вызова.Вы могли бы также написать
Terdon опубликовал несколько слегка модифицированных примеров скриптов в чате :
а также
Запрос был «почему
time ( sh foo.sh | sh bar.sh )
возвращает 4 секунды, а не 3 + 3 = 6 секунд?»Чтобы увидеть, что происходит, включая приблизительное время выполнения каждой команды, можно сделать это (вывод содержит мои аннотации):
Итак, в заключение, конвейер занимает 4 секунды, а не 6, из-за буферизации выходных данных первых двух вызовов
echo
infoo.sh
.источник
ksh93
ожидают только последнего компонента конвейера (sleep 3 | sleep 1
будет длиться 1 секунду). оболочка Bourne не имеетtime
ключевого слова, ноksh93
при запускеtime
все компоненты ожидаются.sleep 10 | sleep 1
занимает одну секунду, аtime sleep 10 | sleep 1
в ksh93 - 10 секунд. В оболочке Bournetime sleep 10 | sleep 1
это заняло бы одну секунду, но через 9 секунд вы получите выходной сигнал времени (sleep 10
только и только/usr/bin/time
).time
правильно рассчитывает конвейер, но меняет поведение оболочки в ksh93.(sleep 10 | sleep 1)
занимает 1 секунду,time (sleep 10 | sleep 1)
занимает 10 секунд.{ (sleep 10 | sleep 1); echo x; }
выходыx
через 1 секунду,time { (sleep 10 | sleep 1); echo x; }
выходыx
через 10 секунд. То же самое, если вы поместите этот код в функцию и время функции.ksh93
как вzsh
(-o promptsubst
здесь), вы можете сделать,typeset -F SECONDS
чтобы получить менее приблизительное количество секунд (POSIXsh
не имеетSECONDS
)Будет ли это лучшим примером?
Сценарии заняты в течение 3 и 4 секунд (соответственно), занимая в общей сложности 4 секунды в режиме реального времени из-за параллельного выполнения и 7 секунд процессорного времени. (хотя бы приблизительно.)
Или это:
Они не работают параллельно, поэтому общее время занимает 5 секунд. Все потрачено на сон, поэтому процессорное время не используется.
источник
Если у вас есть,
sysdig
вы можете вставить трассировщики в произвольные точки, при условии, что вы можете изменить код, чтобы добавить необходимые записи в/dev/null
(но это не соответствует вашему требованию «одной операции»), а затем записывать вещи через
и тогда вам, вероятно, понадобится долото sysdig для экспорта только длительностей
который когда-то сохранен в вашем
sysdig/chisels
каталоге как файлspantagduration.lua
может быть использован какИли вы можете поиграть с
csysdig
или выводом JSON.источник