Como posso executar vários comandos pv em paralelo?

0

Eu quero executar uma seqüência de pipelines de comando com pv em cada um. Aqui está um exemplo:

for p in 1 2 3
do
  cat /dev/zero | pv -N $p | dd of=/dev/null &
done

Os comandos reais no pipe não importam ( cat / dd são apenas um exemplo) ...

A meta é 4 pipelines em execução simultânea, cada uma com sua própria pv output. No entanto, quando tento basear os comandos dessa forma, pv para e tudo que eu recebo são 4 trabalhos interrompidos. Eu tentei com {...|pv|...}& , bash -c "...|pv|..." & todos com o mesmo resultado.

Como posso executar vários pipelines de comando pv simultaneamente?

    
por Josh 28.09.2018 / 18:38

2 respostas

1

Descobri que posso fazer isso com xargs e a opção -P :

josh@subdivisions:/# seq 1 10 | xargs -P 4 -I {} bash -c "dd if=/dev/zero bs=1024 count=10000000 | pv -c -N {} | dd of=/dev/null"
        3: 7.35GiB 0:00:29 [ 280MiB/s] [                                                                                         <=>                                                                 ]
        1: 7.88GiB 0:00:29 [ 312MiB/s] [                                                                                         <=>                                                                 ]
        4: 7.83GiB 0:00:29 [ 258MiB/s] [                                                                                         <=>                                                                 ]
        2: 6.55GiB 0:00:29 [ 238MiB/s] [                                                                                         <=>                                                                 ]

Envie a saída da matriz para iterar em stdin de xargs ; Para executar todos os comandos simultaneamente, use -P 0

    
por 28.09.2018 / 18:45
1

pv não pode ser iniciado em segundo plano.

Como você pode ver no arquivo src/main/main.c do código-fonte de pv , eles são definindo o sinal TOSTOP no terminal com tcsetattr() (no c.c_lflag da estrutura termios ). Eles estão fazendo isso para receber um SIGTTOU ao tentar gravar no terminal quando não estão em primeiro plano, pegá-lo com um manipulador de sinal e redirecionar a saída para /dev/null para não "bagunçar" o terminal .

/*
 * Set terminal option TOSTOP so we get signal SIGTTOU if we try to
 * write to the terminal while backgrounded.
 *
 * Also, save the current terminal attributes for later restoration.
 */
memset(&t, 0, sizeof(t));
tcgetattr(STDERR_FILENO, &t);
t_save = t;
t.c_lflag |= TOSTOP;
tcsetattr(STDERR_FILENO, TCSANOW, &t);

Isso é claro, nojento, porque não define essa bandeira apenas para si, mas para todos os programas que usam o terminal.

Mas isso não é tudo. Como explicado no manual da glibc:

Function: int tcsetattr (int filedes, int when, const struct termios *termios-p)

If this function is called from a background process on its controlling terminal, normally all processes in the process group are sent a SIGTTOU signal, in the same way as if the process were trying to write to the terminal. The exception is if the calling process itself is ignoring or blocking SIGTTOU signals, in which case the operation is performed and no signal is sent. See Job Control.

Eles não estão bloqueando ou ignorando o SIGTTOU . E eles também não estão verificando o valor de retorno de tcsetattr() (que retornaria -1 e definiria errno para EINTR se eles tivessem definido o SIGTTOU manipulador de sinal antes).

Então o processo está parado. Se ele receber um SIGCONT (a partir do comando bg ), ele será parado novamente ao tentar concluir o tcsetattr() .

Então eu acho que você deveria considerar isso um recurso; -)

    
por 28.09.2018 / 23:15