J'ai trois types de données qui sont dans différents formats; pour chaque type de données, il existe un script Python qui le transforme en un seul format unifié.
Ce script Python est lent et lié au CPU (à un seul cœur sur une machine multi-cœur), donc je veux en exécuter trois instances - une pour chaque type de données - et combiner leur sortie pour la transmettre sort
. Fondamentalement, équivalent à ceci:
{ ./handle_1.py; ./handle_2.py; ./handle_3.py } | sort -n
Mais avec les trois scripts fonctionnant en parallèle.
J'ai trouvé cette question où GNU split
était utilisé pour effectuer un round-robin sur un flux standard entre n instances d'un script qui gère le flux.
À partir de la page de manuel fractionnée:
-n, --number=CHUNKS
generate CHUNKS output files. See below
CHUNKS may be:
N split into N files based on size of input
K/N output Kth of N to stdout
l/N split into N files without splitting lines
l/K/N output Kth of N to stdout without splitting lines
r/N like 'l' but use round robin distributio
La r/N
commande implique donc " sans séparer les lignes ".
Sur cette base, il semble que la solution suivante devrait être réalisable:
split -n r/3 -u --filter="./choose_script" << EOF
> 1
> 2
> 3
> EOF
Où choose_script
est-ce:
#!/bin/bash
{ read x; ./handle_$x.py; }
Malheureusement, je vois un mélange de lignes - et beaucoup de nouvelles lignes qui ne devraient pas être là.
Par exemple, si je remplace mes scripts Python par des scripts bash simples qui font ceci:
#!/bin/bash
# ./handle_1.sh
while true; echo "1-$RANDOM"; done;
.
#!/bin/bash
# ./handle_2.sh
while true; echo "2-$RANDOM"; done;
.
#!/bin/bash
# ./handle_3.sh
while true; echo "3-$RANDOM"; done;
Je vois cette sortie:
1-8394
2-11238
2-22757
1-723
2-6669
3-3690
2-892
2-312511-24152
2-9317
3-5981
C'est ennuyeux - sur la base de l'extrait de page de manuel que j'ai collé ci-dessus, il devrait maintenir l'intégrité de la ligne.
Évidemment, cela fonctionne si je supprime l' -u
argument, mais il est mis en mémoire tampon et je manquerai de mémoire car il met en mémoire tampon la sortie de tous les scripts sauf un.
Si quelqu'un a un aperçu ici, ce serait grandement apprécié. Je suis hors de ma profondeur ici.
coproc
module intégré dans bash, bien que je ne vois pas vraiment comment cela s'applique.job1.py > file1 & job2.py > file 2 & job3.py > file3 ; wait ; sort -n file1 file2 file3
?Réponses:
Essayez d'utiliser l'option -u de GNU parallel.
Cela les exécute en parallèle, sans mettre en mémoire tampon l'intégralité d'un processus.
la source
X
àIX
dire-I
que X sera le drapeau pour remplacer, ou applique-t-il le-X
drapeau, qui a apparemment aussi une signification pertinente?parallel -u -X ./handle_{}.sh ::: "1" "2" "3"
:, et malheureusement, je vois toujours des changements de sortie.parallel -u ./handle_{}.sh
, mais je préfère le changer, car les accolades ont également le sens de joindre les commandes (comme dans votre question).Essayer:
Si
handle_1.py
prend un nom de fichier:Vous ne voulez pas que la sortie soit mélangée, alors n'utilisez pas -u.
Si vous souhaitez conserver l'ordre (donc toutes les sorties de handle_1 sont antérieures à handle_2 et vous pourrez ainsi éviter le tri):
Si vous voulez toujours le trier, vous pouvez paralléliser le tri et utiliser
sort -m
:Définissez $ TMPDIR sur un répertoire suffisamment grand pour contenir la sortie.
la source
Peut-être que je manque quelque chose, mais ne pouvez-vous pas simplement faire:
Si vous souhaitez que les lignes de chaque processus ne soient pas entrelacées, le plus simple est probablement de vous assurer que le processus lui-même les écrit complètement et éventuellement de désactiver la mise en mémoire tampon de sortie car
write
s dans un tuyau sont garantis atomiques tant qu'elles ne sont pas plus grandes quePIPE_BUF
. Par exemple, vous pouvez vous assurer qu'il ne utilisation en mémoire tampon de sortie à lastdio
et appelfflush
ou quel que soit l'équivalent estpython
après une ou quelques lignes ont été écrites.Si vous ne pouvez pas modifier les scripts python, vous pouvez faire:
(avec GNU grep) ou:
(Voir les notes dans les commentaires ci-dessous si ce que la sortie des commandes n'est pas du texte)
Et fait:
Une autre option pour éviter ces 3
lb
processus est d'avoir trois canaux vers une commande qui utiliseselect
/poll
pour voir d'où vient une sortie et la nourrir ensort
ligne, mais cela prend un peu de programmation.la source
wait
, je pense.sort -n
restera jusqu'à ce que tous les programmes ayant un fd ouvert se soient fermés.La réponse de Flowbok était la bonne solution. Curieusement, la sortie de GNU
parallel
est altérée si elle est directement envoyée vers un fichier - mais pas si elle va vers un tty.Heureusement,
script -c
est disponible pour imiter un tty.Il y a encore les trois scripts:
.
.
Ensuite, il y a un fichier qui encapsule l'appel à parallèle:
Et puis je l'appelle comme ça:
Les lignes en sortie sont mélangées ligne par ligne entre la sortie des différents scripts, mais elles ne sont pas altérées ou entrelacées sur une ligne donnée.
Comportement bizarre de
parallel
- je peux déposer un rapport de bogue.la source