Wykorzystanie zasobów przy użyciu potoku i tutaj ciągu


16

Możemy uzyskać ten sam wynik, stosując następujące dwa w bash:

echo 'foo' | cat

i

cat <<< 'foo'

Moje pytanie brzmi: jaka jest różnica między tymi dwoma pod względem wykorzystywanych zasobów, a który z nich jest lepszy?

Myślę, że podczas korzystania z potoku używamy dodatkowego procesu echoi potoku, podczas gdy w tym ciągu jest używany tylko deskryptor pliku cat.

Odpowiedzi:


17

Potok jest plikiem otwartym w systemie plików jądra i nie jest dostępny jako zwykły plik na dysku. Jest automatycznie buforowany tylko do określonego rozmiaru i ostatecznie zostanie zablokowany po zapełnieniu. W przeciwieństwie do plików pochodzących z urządzeń blokowych, potoki zachowują się bardzo podobnie do urządzeń znakowych, a więc ogólnie nie obsługują, lseek()a odczytane z nich dane nie mogą być ponownie odczytane, tak jak w przypadku zwykłego pliku.

Ciąg tutaj jest zwykłym plikiem utworzonym w zamontowanym systemie plików. Powłoka tworzy plik i zachowuje swój deskryptor, jednocześnie natychmiast usuwając jedyne łącze do systemu plików (i tak usuwając), zanim zapisuje / odczytuje bajt do / z pliku. Jądro zachowa przestrzeń wymaganą dla pliku, dopóki wszystkie procesy nie zwolnią dla niego wszystkich deskryptorów. Jeśli dziecko czytające z takiego deskryptora ma taką możliwość, można je przewinąć lseek()i przeczytać ponownie.

W obu przypadkach tokeny <<<i |reprezentują deskryptory plików i niekoniecznie same pliki. Możesz uzyskać lepszy obraz tego, co się dzieje, wykonując takie czynności, jak:

readlink /dev/fd/1 | cat

...lub...

ls -l <<<'' /dev/fd/*

Najistotniejsza różnica między tymi dwoma plikami polega na tym, że ciąg tutaj / dokument jest właściwie sprawą naraz - powłoka zapisuje w nim wszystkie dane przed przekazaniem deskryptora odczytu dziecku. Z drugiej strony powłoka otwiera potok na odpowiednich deskryptorach i odradza dzieciom zarządzanie tymi dla potoku - tak więc jest on zapisywany / odczytywany jednocześnie na obu końcach.

Te rozróżnienia są jednak ogólnie prawdziwe. O ile mi wiadomo (co tak naprawdę nie jest aż tak daleko), dotyczy to praktycznie każdej powłoki, która obsługuje <<<skrót <<tutaj do przekierowania dokumentu tutaj z jednym wyjątkiem yash. yash, busybox, dash, Oraz inne ashwarianty mają tendencję do tu-dokumentów z rur, choć i tak w tych muszli tam naprawdę jest bardzo mała różnica między nimi po wszystkim.

Ok - dwa wyjątki. Teraz, gdy o tym myślę, ksh93tak naprawdę nie robi potoku dla |, ale obsługuje cały biznes z gniazdami - chociaż robi usunięty plik tmp dla <<<*większości innych. Co więcej, umieszcza tylko oddzielne sekcje potoku w środowisku podpowłoki, która jest rodzajem eufemizmu POSIX, ponieważ przynajmniej działa jak podpowłoka , a więc nawet nie robi forks.

Faktem jest, że wyniki testu porównawczego @ PSkocik (co jest bardzo przydatne) mogą się znacznie różnić z wielu powodów, a większość z nich zależy od implementacji. W przypadku konfiguracji dokumentu tutaj najważniejszymi czynnikami będą docelowy ${TMPDIR}typ systemu plików i bieżąca konfiguracja / dostępność pamięci podręcznej, a także nadal ilość zapisywanych danych. W przypadku potoku będzie to rozmiar samego procesu powłoki, ponieważ wykonywane są kopie wymaganych widelców. W ten sposób bashjest okropny przy ustawianiu potoków (w tym zastępowanie $(poleceń )) - ponieważ jest duży i bardzo wolny, ale z ksh93tym nie robi prawie żadnej różnicy.

Oto kolejny mały fragment powłoki pokazujący, w jaki sposób powłoka dzieli podpowłoki dla potoku:

pipe_who(){ echo "$$"; sh -c 'echo "$PPID"'; }
pipe_who
pipe_who | { pipe_who | cat /dev/fd/3 -; } 3<&0

32059  #bash's pid
32059  #sh's ppid
32059  #1st subshell's $$
32111  #1st subshell sh's ppid
32059  #2cd subshell's $$
32114  #2cd subshell sh's ppid

Różnica między tym, co pipe_who()raportuje wywołanie potokowe , a raportem z jednego uruchomienia w bieżącej powłoce wynika (z )określonego zachowania podpowłoki, polegającego na żądaniu pid powłoki macierzystej, $$gdy jest ona rozwinięta. Chociaż bashpodpowłoki zdecydowanie są oddzielnymi procesami, $$specjalny parametr powłoki nie jest wiarygodnym źródłem tych informacji. Mimo to potomna shskorupa podpowłoki nie odmawia dokładnego zgłoszenia jej $PPID.


Bardzo pomocny. System plików w jądrze, czy jest na to nazwa? czy to znaczy, że istnieje w przestrzeni jądra?
utlamn

2
@utlamn - właściwie tak - po prostu pipefs . Wszystko jest wbudowane w jądro - ale (oprócz takich rzeczy jak FUSE), podobnie jak wszystkie pliki we / wy .
mikeserv

10

Nie ma substytutu dla testów porównawczych:

pskocik@ProBook:~ 
$ time (for((i=0;i<1000;i++)); do cat<<< foo >/dev/null; done  )

real    0m2.080s
user    0m0.738s
sys 0m1.439s
pskocik@ProBook:~ 
$ time (for((i=0;i<1000;i++)); do echo foo |cat >/dev/null; done  )

real    0m4.432s
user    0m2.095s
sys 0m3.927s
$ time (for((i=0;i<1000;i++)); do cat <(echo foo) >/dev/null; done  )
real    0m3.380s
user    0m1.121s
sys 0m3.423s

A dla większej ilości danych:

TENMEG=$(ruby -e 'puts "A"*(10*1024*1024)')
pskocik@ProBook:~ 
$ time (for((i=0;i<100;i++)); do echo "$TENMEG" |cat >/dev/null; done  )

real    0m42.327s
user    0m38.591s
sys 0m4.226s
pskocik@ProBook:~ 
$ time (for((i=0;i<100;i++)); do cat<<< "$TENMEG" >/dev/null; done  )

real    1m26.946s
user    1m23.116s
sys 0m3.681s
pskocik@ProBook:~ 

$ time (for((i=0;i<100;i++)); do cat <(echo "$TENMEG") >/dev/null; done  )

real    0m43.910s
user    0m40.178s
sys 0m4.119s

Wygląda na to, że wersja rury ma większy koszt instalacji, ale ostatecznie jest bardziej wydajna.


@mikeserv To było poprawne. Dodałem test porównawczy z większą ilością danych.
PSkocik,

2
echo foo >/dev/shm/1;cat /dev/shm/1 >/dev/nullwydawało się być szybkie w obu przypadkach ...
user23013

@ user23013 To ma sens. Nie widzę dlaczego albo echo "$longstring"czy <<<"$longstring"będzie manipulowane za efektywność i krótkie ciągi, wydajność nie ma większego znaczenia i tak.
PSkocik,

Ciekawe, że w moim przypadku (na Ubuntu 14.04, czterordzeniowy Intel i7) cat <(echo foo) >/dev/nulljest szybszy niż echo foo | cat >/dev/null.
pabouk

1
@Prem Tak, byłoby to lepsze podejście, ale jeszcze lepszym byłoby nie przejmowanie się tym i używanie odpowiedniego narzędzia do pracy. Nie ma powodu sądzić, że heredoki zostaną dostosowane do wydajności.
PSkocik
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.