Quando scrivi A | B
, entrambi i processi già eseguiti in parallelo. Se li vedi utilizzando solo un core, probabilmente è a causa delle impostazioni di affinità della CPU (forse c'è qualche strumento per generare un processo con affinità diversa) o perché un processo non è sufficiente per contenere un intero core e il sistema " preferisce "non diffondere il calcolo.
Per eseguire diverse B con una A, è necessario uno strumento come split
con l' --filter
opzione:
A | split [OPTIONS] --filter="B"
Questo, tuttavia, rischia di incasinare l'ordine delle linee nell'output, perché i lavori B non verranno eseguiti tutti alla stessa velocità. Se questo è un problema, potrebbe essere necessario reindirizzare l'output B in un file intermedio e cucirli insieme alla fine usando cat
. Questo, a sua volta, può richiedere un notevole spazio su disco.
Esistono altre opzioni (ad esempio, è possibile limitare ciascuna istanza di B a un output con buffer a riga singola, attendere fino al termine di un intero "giro" di B, eseguire l'equivalente di una riduzione per split
la mappa e cat
l'output temporaneo insieme), con diversi livelli di efficienza. L'opzione 'round' appena descritta, ad esempio, attenderà il completamento dell'istanza più lenta di B , quindi dipenderà fortemente dal buffering disponibile per B; [m]buffer
potrebbe aiutare, oppure no, a seconda delle operazioni.
Esempi
Genera i primi 1000 numeri e conta le linee in parallelo:
seq 1 1000 | split -n r/10 -u --filter="wc -l"
100
100
100
100
100
100
100
100
100
100
Se dovessimo "contrassegnare" le linee, vedremmo che ogni prima riga viene inviata al processo n. 1, ogni quinta riga al processo n. 5 e così via. Inoltre, nel tempo necessario split
per generare il secondo processo, il primo è già un buon modo per la sua quota:
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
Quando si esegue su una macchina a 2 core seq
, split
i wc
processi condividono i core; ma guardando più da vicino, il sistema lascia i primi due processi su CPU0 e divide CPU1 tra i processi di lavoro:
%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
Si noti in particolare che split
sta consumando una notevole quantità di CPU. Ciò diminuirà in proporzione alle esigenze di A; cioè, se A è un processo più pesante di seq
, il relativo sovraccarico split
diminuirà. Ma se A è un processo molto leggero e B è piuttosto veloce (quindi non hai bisogno di più di 2-3 B per tenerlo insieme ad A), allora la parallelizzazione con split
(o i tubi in generale) potrebbe non valerne la pena.
A | B | C
è parallelo come in processi separati, a causa della natura dei tubi (B deve attendere l'uscita di A, C deve attendere l'uscita di B) in alcuni casi può essere comunque lineare. Dipende interamente dal tipo di output che producono. Non ci sono molti casi in cui l'esecuzione di piùB
potrebbe essere di grande aiuto, è del tutto possibile che l'esempio di wc parallelo sia più lento del normalewc
poiché la divisione può richiedere più risorse rispetto al conteggio delle linee normalmente. Usare con cura.