web-dev-qa-db-fra.com

Exécuter des commandes de canette en parallèle

Considérez le scénario suivant. J'ai deux programmes A et B. Programmez une sortie sur des lignes de strings STDOUT, tandis que le programme B traite des lignes de STDIN. Le moyen d'utiliser ces deux programmes est bien sûr:

foo @ bar: ~ $ a | B

Maintenant, j'ai remarqué que cela ne mange qu'un seul noyau; Par conséquent, je me demande:

Les programmes A et B partagent-ils les mêmes ressources de calcul? Si oui, est-il un moyen de courir un et B simultanément?

Une autre chose que j'ai remarquée est qu'une course beaucoup plus vite que B, donc je me demande si cela pouvait en quelque sorte exécuter plus de programmes B et les laisser traiter les lignes d'une sortie en parallèle.

C'est-à-dire que A émettrait ses lignes et il y aurait n des instances de programmes B qui liraient ces lignes (qui les lit en premier) les traitent et les émettent d'abord) et de les produire sur stdout.

Donc, ma dernière question est la suivante:

Existe-t-il un moyen de piloter la sortie à un de plusieurs processus B sans avoir à s'occuper des conditions de race et d'autres incohérences susceptibles de se poser?

17
Jernej

Un problème avec split --filter Est-ce que la sortie peut être mélangée, vous obtenez donc une demi-ligne à partir du processus 1 suivie d'une demi-ligne du processus 2.

GTNU garanties parallèles Il n'y aura pas de mixup.

Alors supposez que vous voulez faire:

 A | B | C

Mais ce B est terriblement lent et que vous voulez donc paralléliser cela. Ensuite, vous pouvez faire:

A | parallel --pipe B | C

GNU parallèle par défaut divise sur\n et une taille de bloc de 1 Mo. Cela peut être ajusté avec --Recend and --Block.

Vous pouvez en trouver plus sur GNU parallèle à: http://www.gnu.org/s/parallel/

Vous pouvez installer GNU parallel dans seulement 10 secondes avec:

$ (wget -O - pi.dk/3 || lynx -source pi.dk/3 || curl pi.dk/3/ || \
   fetch -o - http://pi.dk/3 ) > install.sh
$ sha1sum install.sh | grep 3374ec53bacb199b245af2dda86df6c9
12345678 3374ec53 bacb199b 245af2dd a86df6c9
$ md5sum install.sh | grep 029a9ac06e8b5bc6052eac57b2c3c9ca
029a9ac0 6e8b5bc6 052eac57 b2c3c9ca
$ sha512sum install.sh | grep f517006d9897747bed8a4694b1acba1b
40f53af6 9e20dae5 713ba06c f517006d 9897747b ed8a4694 b1acba1b 1464beb4
60055629 3f2356f3 3e9c4e3c 76e3f3af a9db4b32 bd33322b 975696fc e6b23cfb
$ bash install.sh

Regardez l'intro vidéo sur http://www.youtube.com/playlist?list=pl284C9FF2488BC6D1

15
Ole Tange

Quand vous écrivez A | B, les deux processus déjà Run en parallèle. Si vous les voyez comme n'utilisant qu'un seul noyau, c'est probablement parce que l'un des réglages d'affinité de la CPU (peut-être un outil d'apparition d'un processus avec une affinité différente) ou parce qu'un processus ne suffit pas pour contenir un noyau entier et le système " préfère "ne pas répandre l'informatique.

Pour exécuter plusieurs B avec un A, vous avez besoin d'un outil tel que split avec le --filter Option:

A | split [OPTIONS] --filter="B"

Toutefois, cela est susceptible de gâcher l'ordre des lignes dans la sortie, car les emplois B ne seront pas à la même vitesse. S'il s'agit d'un problème, vous devrez peut-être rediriger B i-e sortie dans un fichier intermédiaire et les coudre ensemble à la fin en utilisant cat. Ceci, à son tour, peut nécessiter un espace disque considérable.

D'autres options existent (par exemple, vous pouvez limiter chaque instance de B sur une seule sortie tamponnée à la ligne, attendre que tout un "cycle" de B de B a fini, exécutez l'équivalent d'A Réduire à split 's map et cat la sortie temporaire ensemble), avec des niveaux d'efficacité variables. L'option "ronde" vient de décrire par exemple attendra l'instance l'instance la plus lente de B Pour terminer, il sera donc fortement dépendant de la mémoire tampon disponible pour B; [m]buffer Peut aider, ou cela pourrait ne pas, en fonction de ce que sont les opérations.

Exemples

Générez les 1000 premiers nombres et compter les lignes en parallèle:

seq 1 1000 | split -n r/10 -u --filter="wc -l"
100
100
100
100
100
100
100
100
100
100

Si nous devions "marquer" les lignes, nous verrions que chaque première ligne soit envoyée au processus n ° 1, chaque cinquième ligne à traiter n ° 5 et ainsi de suite. De plus, dans le temps qu'il faut split pour reproduire le deuxième processus, le premier est déjà un bon moyen dans son 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

Lors de l'exécution sur une machine à 2 cœurs, seq, split et les processus wc partagent les cœurs; Mais à la recherche de plus près, le système quitte les deux premiers processus sur CPU0 et divise la CPU1 parmi les processus de travail:

%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

Notez notamment que split mange une quantité considérable de processeur. Cela diminuera proportionnellement aux besoins de A; C'est-à-dire que si A est un processus plus lourd que seq, le surcharge relatif de split va diminuer. mais Si A est un processus très léger et B est assez rapide (de sorte que vous n'avez pas besoin de plus de 2-3 b pour rester avec a), puis en parallèle avec split (ou Tuyaux en général) Peut-être Bien ne valez pas la peine.

13
LSerni