Quando você escreve A | B
, ambos os processos já são executados em paralelo. Se você os vir usando apenas um núcleo, isso provavelmente se deve às configurações de afinidade da CPU (talvez haja alguma ferramenta para gerar um processo com afinidade diferente) ou porque um processo não é suficiente para manter um núcleo inteiro e o sistema " prefere "não espalhar a computação.
Para executar vários B's com um A, você precisa de uma ferramenta como split
com a opção --filter
:
A | split [OPTIONS] --filter="B"
Isso, no entanto, pode estragar a ordem das linhas na saída, porque as tarefas B não estarão rodando todas na mesma velocidade. Se isso for um problema, talvez seja necessário redirecionar a saída B i-th para um arquivo intermediário e juntá-los no final usando cat
. Isso, por sua vez, pode exigir um espaço considerável em disco.
Existem outras opções (por exemplo, você poderia limitar cada instância de B a uma única saída com buffer de linha, esperar até que uma "rodada" inteira de B tenha terminado, executar o equivalente a reduzir a% o mapa dosplit
, e cat
a saída temporária em conjunto), com vários níveis de eficiência. A opção 'round' que acabamos de descrever, por exemplo, irá aguardar a conclusão da instância mais lenta de B , de modo que será muito dependente do buffering disponível para B; [m]buffer
pode ajudar, ou talvez não, dependendo de quais são as operações.
Exemplos
Gere os primeiros 1000 números e conte as linhas em paralelo:
seq 1 1000 | split -n r/10 -u --filter="wc -l"
100
100
100
100
100
100
100
100
100
100
Se fôssemos "marcar" as linhas, veríamos que cada primeira linha é enviada para processar # 1, cada quinta linha para processar # 5 e assim por diante. Além disso, no tempo que leva split
para gerar o segundo processo, o primeiro já é um bom caminho para sua cota:
seq 1 1000 | split -n r/10 -u --filter="sed -e 's/^/$RANDOM - /g'" | head -n 10
19190 - 1
19190 - 11
19190 - 21
19190 - 31
19190 - 41
19190 - 51
19190 - 61
19190 - 71
19190 - 81
Ao executar em uma máquina de 2 núcleos, os processos seq
, split
e wc
compartilham os núcleos; mas olhando mais de perto, o sistema deixa os dois primeiros processos na CPU0 e divide a CPU1 entre os processos de trabalho:
%Cpu0 : 47.2 us, 13.7 sy, 0.0 ni, 38.1 id, 1.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu1 : 15.8 us, 82.9 sy, 0.0 ni, 1.0 id, 0.0 wa, 0.3 hi, 0.0 si, 0.0 st
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
5314 lserni 20 0 4516 568 476 R 23.9 0.0 0:03.30 seq
5315 lserni 20 0 4580 720 608 R 52.5 0.0 0:07.32 split
5317 lserni 20 0 4520 576 484 S 13.3 0.0 0:01.86 wc
5318 lserni 20 0 4520 572 484 S 14.0 0.0 0:01.88 wc
5319 lserni 20 0 4520 576 484 S 13.6 0.0 0:01.88 wc
5320 lserni 20 0 4520 576 484 S 13.3 0.0 0:01.85 wc
5321 lserni 20 0 4520 572 484 S 13.3 0.0 0:01.84 wc
5322 lserni 20 0 4520 576 484 S 13.3 0.0 0:01.86 wc
5323 lserni 20 0 4520 576 484 S 13.3 0.0 0:01.86 wc
5324 lserni 20 0 4520 576 484 S 13.3 0.0 0:01.87 wc
Observe especialmente que split
está comendo uma quantidade considerável de CPU. Isso diminuirá proporcionalmente às necessidades de A; ou seja, se A for um processo mais pesado que seq
, a sobrecarga relativa de split
diminuirá. Mas se A é um processo muito leve e B é bastante rápido (para que você não precise de mais do que 2-3 Bs para manter junto com A), então paralelizar com split
(ou tubos em geral ) pode não valer a pena.