Quando você escreve A | B
, os dois processos já são executados em paralelo. Se você vê-los usando apenas um núcleo, provavelmente é por causa das 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 armazenar 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
a --filter
opção:
A | split [OPTIONS] --filter="B"
No entanto, isso pode atrapalhar a ordem das linhas na saída, porque os trabalhos B não serão executados todos na mesma velocidade. Se este for um problema, pode ser necessário redirecionar a saída i para um arquivo intermediário e costurá-las no final usando cat
. Por sua vez, isso pode exigir um espaço considerável em disco.
Existem outras opções (por exemplo, você pode limitar cada instância de B a uma única saída com buffer de linha, esperar até que toda uma "rodada" de B seja concluída, executar o equivalente a uma redução no mapa desplit
s e a saída temporária em conjunto), com níveis variados de eficiência. A opção 'round' descrita acima, por exemplo, aguardará a conclusão da instância mais lenta de B , portanto, dependerá muito do buffer disponível para B; pode ajudar, ou não, dependendo de quais são as operações.cat
[m]buffer
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 "marcássemos" as linhas, veríamos que cada primeira linha é enviada para o processo 1, cada quinta linha para o processo 5 e assim por diante. Além disso, no tempo necessário 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 numa máquina de dois núcleos, seq
, split
e os wc
processos 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á consumindo uma quantidade considerável de CPU. Isso diminuirá proporcionalmente às necessidades de A; isto é, se A for um processo mais pesado que seq
, a sobrecarga relativa 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 B's para acompanhar A), paralelizar com split
(ou tubos em geral) pode não valer a pena.
A | B | C
seja paralelo como em processos separados, devido à natureza dos tubos (B precisa aguardar a saída de A, C deve aguardar a saída de B), ainda pode ser linear em alguns casos. Depende inteiramente do tipo de produção que eles produzem. Não há muitos casos em que executar múltiplosB
ajudaria muito, é perfeitamente possível que o exemplo wc paralelo seja mais lento que o normal,wc
pois a divisão pode levar mais recursos do que contar linhas normalmente. Use com cuidado.