Diferenças de desempenho entre pipelines e substituição de processos

6

Eu costumo usar pipelines em meus scripts bash sobre a substituição de processos na maioria das situações, especialmente em casos de usar vários conjuntos de comandos, pois parece mais legível fazer ... | ... | ... over ... < <(... < <(...)) .

No entanto, estou me perguntando por que usar a substituição de processos é muito mais rápido em algumas situações do que usar um pipeline.

Para testar isso, eu time d dois scripts usando 10000 iterações dos mesmos comandos anexados com um usando um pipeline e outro usando a substituição do processo.

Scripts:

pipeline.bash :

for i in {1..10000}; do
    echo foo bar |
    while read; do
        echo $REPLY >/dev/null
    done
done

proc-sub.bash

for i in {1..10000}; do
    while read; do
        echo $REPLY >/dev/null
    done < <(echo foo bar)
done

Resultados:

~$ time ./pipeline.bash

real    0m17.678s
user    0m14.666s
sys     0m14.807s

~$ time ./proc-sub.bash

real    0m8.479s
user    0m4.649s
sys     0m6.358s

Sei que os pipelines criam um subprocesso, enquanto a substituição de processos cria um canal nomeado ou algum arquivo em /dev/fd , mas não está claro como essas diferenças afetam o desempenho.

    
por John B 03.05.2014 / 05:10

1 resposta

8

Fazendo o mesmo strace , você pode ver as diferenças:

com pipe :

$ strace -c ./pipe.sh 
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 57.89    0.103005           5     20000           clone
 40.81    0.072616           2     30000     10000 wait4
  0.58    0.001037           0    120008           rt_sigprocmask
  0.40    0.000711           0     10000           pipe

com proc-sub :

$ strace -c ./procsub.sh 
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 85.08    0.045502           5     10000           clone
  3.25    0.001736           0     90329       322 read
  2.12    0.001133           0     20009           open
  2.03    0.001086           0     50001           dup2

Com as estatísticas acima, você pode ver pipe criar mais processos filho ( clone syscall) e gastar muitas vezes para esperar que o processo filho ( wait4 syscall) termine o processo pai continuar a execução.

Process substitution não é. Pode ler diretamente dos processos filhos. Process substitution é executado ao mesmo tempo com a expansão de parâmetro e variável, o comando em Process Substitution é executado em segundo plano. De bash manpage :

Process Substitution
       Process  substitution  is supported on systems that support named pipes
       (FIFOs) or the /dev/fd method of naming open files.  It takes the  form
       of  <(list) or >(list).  The process list is run with its input or out‐
       put connected to a FIFO or some file in /dev/fd.  The name of this file
       is  passed  as  an argument to the current command as the result of the
       expansion.  If the >(list) form is used, writing to the file will  pro‐
       vide  input  for list.  If the <(list) form is used, the file passed as
       an argument should be read to obtain the output of list.

       When available, process substitution is performed  simultaneously  with
       parameter  and variable expansion, command substitution, and arithmetic
       expansion.

Atualizar

Fazendo strace com estatísticas de processos filhos:

com pipe :

$ strace -fqc ./pipe.sh 
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 70.76    0.215739           7     30000     10000 wait4
 28.04    0.085490           4     20000           clone
  0.78    0.002374           0    220008           rt_sigprocmask
  0.17    0.000516           0    110009     20000 close
  0.15    0.000456           0     10000           pipe

com proc-sub :

$ strace -fqc ./procsub.sh 
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 52.38    0.033977           3     10000           clone
 32.24    0.020913           0     96070      6063 read
  5.24    0.003398           0     20009           open
  2.34    0.001521           0    110003     10001 fcntl
  1.87    0.001210           0    100009           close
    
por 03.05.2014 / 07:26