파이프 시간을 어떻게 정할 수 있습니까?


27

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실행하는 데 걸린 시간을 계산하지 않는 것 같습니다 1 .bar.sh

모든 테스트는 아치 시스템에서 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출력.


실제 스톱워치로 사용해 보셨습니까?
pericynthion

@ pericynthion yep 결국 나는했다. 그리고 그것은 대답이 설명하는 것을 보여주었습니다. 시간은 실제로 작동하지만 파이프 라인의 명령은 동시에 실행되므로 소요 시간은 본질적으로 가장 느린 시간입니다.
terdon

답변:


33

그것은 되는 작업입니다.

파이프 라인의 여러 부분이 동시에 실행됩니다. 파이프 라인의 프로세스를 동기화 / 직렬화하는 유일한 것은 IO입니다. 즉, 파이프 라인의 다음 프로세스에 쓰는 하나의 프로세스와 첫 번째 프로세스가 쓰는 것을 읽는 다음 프로세스입니다. 그 외에도 그들은 독립적 으로 실행 됩니다.

파이프 라인의 프로세스 간에는 읽거나 쓰는 것이 없으므로 파이프 라인을 실행하는 데 걸리는 시간은 가장 긴 sleep호출 시간입니다.

당신은뿐만 아니라 작성했을 수 있습니다

time ( foo.sh & bar.sh &; wait )

Terdon은 채팅에 약간 수정 된 예제 스크립트를 게시 했습니다 .

#!/bin/sh
# This is "foo.sh"
echo 1; sleep 1
echo 2; sleep 1
echo 3; sleep 1
echo 4

#!/bin/sh
# This is "bar.sh"
sleep 2
while read line; do
  echo "LL $line"
done
sleep 1

" time ( sh foo.sh | sh bar.sh )3 + 3 = 6 초가 아닌 4 초를 반환하는 이유는 무엇입니까?"

각 명령이 실행되는 대략적인 시간을 포함하여 현재 상황을 확인하려면 다음과 같이하십시오 (출력에 내 주석이 포함됨).

$ time ( env PS4='$SECONDS foo: ' sh -x foo.sh | PS4='$SECONDS bar: ' sh -x bar.sh )
0 bar: sleep 2
0 foo: echo 1     ; The output is buffered
0 foo: sleep 1
1 foo: echo 2     ; The output is buffered
1 foo: sleep 1
2 bar: read line  ; "bar" wakes up and reads the two first echoes
2 bar: echo LL 1
LL 1
2 bar: read line
2 bar: echo LL 2
LL 2
2 bar: read line  ; "bar" waits for more
2 foo: echo 3     ; "foo" wakes up from its second sleep
2 bar: echo LL 3
LL 3
2 bar: read line
2 foo: sleep 1
3 foo: echo 4     ; "foo" does the last echo and exits
3 bar: echo LL 4
LL 4
3 bar: read line  ; "bar" fails to read more
3 bar: sleep 1    ; ... and goes to sleep for one second

real    0m4.14s
user    0m0.00s
sys     0m0.10s

결론적으로, 파이프 라인은 echoin 의 처음 두 호출의 출력 버퍼링으로 인해 6이 아니라 4 초가 걸립니다 foo.sh.


1
@terdon 값은 합계이지만 스크립트는 사용자 및 시스템 시간이 거의 걸리지 않습니다. 대기 시간은 계산되지 않습니다 (벽시계 시간 제외).
Stephen Kitt

2
Bourne 쉘과 같은 일부 쉘 ksh93은 파이프 라인의 마지막 구성 요소 만 기다립니다 ( sleep 3 | sleep 11 초 지속). Bourne 쉘에는 time키워드가 없지만로 ksh93실행 time되면 모든 구성 요소가 대기합니다.
Stéphane Chazelas

3
ksh93에서 1 초가 걸리고 10 초가 걸린다 sleep 10 | sleep 1는 사실에 놀랐을 것입니다 time sleep 10 | sleep 1. Bourne 쉘에서는 time sleep 10 | sleep 11 초가 걸리지 sleep 10만, /usr/bin/time9 초 후에 파란색 에서 시간 출력 만 표시됩니다 .
Stéphane Chazelas

1
그것은 아무것도 지키는 것이 아닙니다. time파이프 라인의 시간을 올바르게 지정하지만 ksh93에서 쉘의 동작을 변경합니다. (sleep 10 | sleep 1)1 time (sleep 10 | sleep 1)초 걸리고 10 초 걸립니다. { (sleep 10 | sleep 1); echo x; }출력 x일초 후에, time { (sleep 10 | sleep 1); echo x; }출력 x10 초 후에. 해당 코드를 함수에 넣고 함수 시간을 정하면 동일합니다.
Stéphane Chazelas

1
에 있습니다 ksh93같은에서 zsh( -o promptsubst여기), 당신이 할 수있는 typeset -F SECONDS덜받을 대략적인 (POSIX 초 수를 sh더이 없습니다 SECONDS)
스테판 Chazelas가

10

이것이 더 좋은 예일까요?

$ time perl -e 'alarm(3); 1 while 1;' | perl -e 'alarm(4); 1 while 1;'
Alarm clock

real    0m4.004s
user    0m6.992s
sys     0m0.004s

스크립트는 3 초 및 4 초 (통상) 동안 반복 실행되며 병렬 실행으로 인해 총 4 초, CPU 시간은 7 초가 소요됩니다. (적어도 대략.)

아니면 이거:

$ time ( sleep 2; echo) | ( read x; sleep 3 )

real    0m5.004s
user    0m0.000s
sys     0m0.000s

이들은 병렬로 실행되지 않으므로 총 소요 시간은 5 초입니다. 모두 잠들었으므로 CPU 시간을 사용하지 않았습니다.


3

당신이 있다면 sysdig당신은 추적자를 삽입 할 수 있습니다 당신이 필요한 쓰기를 추가하는 코드를 수정할 수 있습니다 가정, 임의의 지점에서/dev/null

echo '>::blah::' >/dev/null
foo.sh | bar.sh
echo '<::blah::' >/dev/null

(하지만 "단일 작업"요구 사항에 실패한 경우)

$ sudo sysdig -w blalog "span.tags contains blah"

그런 다음 지속 시간을 내보내려면 sysdig 끌이 필요할 것입니다.

description = "Exports sysdig span tag durations";
short_description = "Export span tag durations.";
category = "Tracers";

args = {}

function on_init()
    ftags = chisel.request_field("span.tags")
    flatency = chisel.request_field("span.duration")
    chisel.set_filter("evt.type=tracer and evt.dir=<")
    return true
end

function on_event()
    local tags = evt.field(ftags)
    local latency = evt.field(flatency)
    if latency then
        print(tostring(tags) .. "\t" .. tonumber(latency) / 1e9)
    end
    return true
end

한 번 sysdig/chisels파일로 디렉토리에 저장하면 다음 과 같이 spantagduration.lua사용할 수 있습니다

$ sysdig -r blalog -c spantagduration
...

또는 csysdigJSON 출력으로 놀 수도 있습니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.