Chcę time
polecenia składającego się z dwóch oddzielnych poleceń z jednym wyjściem potokowym do drugiego. Weźmy na przykład dwa poniższe skrypty:
$ cat foo.sh
#!/bin/sh
sleep 4
$ cat bar.sh
#!/bin/sh
sleep 2
Jak mogę time
zgłosić czas foo.sh | bar.sh
(i tak, wiem, że fajka nie ma tutaj sensu, ale to tylko przykład)? Działa zgodnie z oczekiwaniami, jeśli uruchamiam je sekwencyjnie w podpowłoce bez instalacji:
$ time ( foo.sh; bar.sh )
real 0m6.020s
user 0m0.010s
sys 0m0.003s
Ale nie mogę go uruchomić podczas instalacji:
$ 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
Przeczytałem podobne pytanie ( Jak uruchomić czas na wielu poleceniach ORAZ zapisać czas wyjściowy do pliku? ), A także wypróbowałem samodzielny time
plik wykonywalny:
$ /usr/bin/time -p sh -c "foo.sh | bar.sh"
real 4.01
user 0.00
sys 0.00
To nawet nie działa, jeśli utworzę trzeci skrypt, który uruchamia tylko potok:
$ cat baz.sh
#!/bin/sh
foo.sh | bar.sh
A potem czas, że:
$ time baz.sh
real 0m4.009s
user 0m0.003s
sys 0m0.000s
Co ciekawe, nie wydaje się, że time
kończy się natychmiast po wykonaniu pierwszego polecenia. Jeśli zmienię bar.sh
na:
#!/bin/sh
sleep 2
seq 1 5
I time
znowu spodziewałem się, że time
wydruk zostanie wydrukowany przed, seq
ale nie jest to:
$ time ( { foo.sh | bar.sh; } )
1
2
3
4
5
real 0m4.005s
user 0m0.003s
sys 0m0.000s
Wygląda na to, time
że nie liczy czasu wykonania bar.sh
pomimo oczekiwania na zakończenie przed wydrukowaniem raportu 1 .
Wszystkie testy zostały uruchomione w systemie Arch i przy użyciu wersji bash 4.4.12 (1). Mogę użyć bash tylko do projektu, który jest częścią tego, więc nawet jeśli zsh
jakaś inna potężna powłoka może go obejść, nie będzie to dla mnie realnym rozwiązaniem.
Jak mogę uzyskać czas potrzebny na uruchomienie zestawu potoków? A skoro już to robimy, dlaczego to nie działa? Wygląda na to, że time
natychmiast kończy działanie, gdy tylko zakończy się pierwsze polecenie. Czemu?
Wiem, że mogę uzyskać indywidualne czasy za pomocą czegoś takiego:
( time foo.sh ) 2>foo.time | ( time bar.sh ) 2> bar.time
Ale nadal chciałbym wiedzieć, czy jest możliwe, aby całość czasu zaplanować jako pojedynczą operację.
1 To nie wydaje się być problemem z buforem, próbowałem uruchomić skrypty z, unbuffered
a stdbuf -i0 -o0 -e0
liczby były nadal drukowane przed time
wyjściem.
Odpowiedzi:
To jest praca.
Różne części potoku są wykonywane jednocześnie. Jedyną rzeczą, która synchronizuje / szereguje procesy w potoku jest IO, tj. Jeden proces zapisujący do następnego procesu w potoku i następny proces czytający to, co pisze pierwszy. Oprócz tego wykonują się niezależnie od siebie.
Ponieważ między procesami w potoku nie ma odczytu ani zapisu, czas jego wykonania jest najdłuższy
sleep
.Równie dobrze mógłbyś napisać
Terdon opublikował kilka nieznacznie zmodyfikowanych przykładowych skryptów na czacie :
i
Zapytanie brzmiało: „dlaczego
time ( sh foo.sh | sh bar.sh )
zwraca 4 sekundy zamiast 3 + 3 = 6 sekund?”Aby zobaczyć, co się dzieje, w tym przybliżony czas wykonania każdego polecenia, można to zrobić (wynik zawiera moje adnotacje):
Tak więc, aby stwierdzić, rurociąg trwa 4 sekundy, a nie 6, ze względu na buforowanie wyjścia z dwóch pierwszych połączeń do
echo
wfoo.sh
.źródło
ksh93
tylko czekają na ostatni komponent potoku (sleep 3 | sleep 1
trwałby 1 sekundę). powłoka Bourne'a nie matime
słowa kluczowego, aleksh93
podczas działania ztime
wszystkimi komponentami są czekane.sleep 10 | sleep 1
zajmuje to sekundę, atime sleep 10 | sleep 1
10 sekund. W powłoce Bourne'a zabrałobytime sleep 10 | sleep 1
to sekundę, ale otrzymałeś wynik czasu (sleep 10
tylko i od/usr/bin/time
) z niebieskiego 9 sekund później.time
poprawnie razy potokuje potok, ale zmienia zachowanie powłoki w ksh93.(sleep 10 | sleep 1)
zajmuje 1 sekundę,time (sleep 10 | sleep 1)
zajmuje 10 sekund.{ (sleep 10 | sleep 1); echo x; }
wyjściax
po 1 sekundzie,time { (sleep 10 | sleep 1); echo x; }
wyjściax
po 10 sek. To samo, jeśli umieścisz ten kod w funkcji i czas funkcji.ksh93
jak wzsh
(-o promptsubst
tutaj), możesz zrobić,typeset -F SECONDS
aby uzyskać mniej przybliżoną liczbę sekund (POSIXsh
nie maSECONDS
)Czy byłby to lepszy przykład?
Skrypty busyloop trwają 3 i 4 sekundy (odpowiednio), zajmując łącznie 4 sekundy w czasie rzeczywistym z powodu równoległego wykonywania i 7 sekund czasu procesora. (przynajmniej w przybliżeniu.)
Albo to:
Nie działają one równolegle, więc całkowity czas to 5 sekund. Wszystko to spędza się na spaniu, więc nie potrzeba czasu procesora.
źródło
Jeśli masz
sysdig
, możesz wstawiać znaczniki w dowolnych punktach, zakładając, że możesz zmodyfikować kod, aby dodać niezbędne zapisy/dev/null
(ale to nie spełnia wymogu „pojedynczej operacji”), a następnie rejestruje rzeczy za pośrednictwem
i wtedy prawdopodobnie będziesz potrzebował dłuta sysdig, aby wyeksportować tylko czasy
które kiedyś zapisano w
sysdig/chisels
katalogu jako plikspantagduration.lua
może być użyty jakoMożesz też pobawić się
csysdig
wyjściem JSON lub.źródło