異なる形式の3種類のデータがあります。データ型ごとに、それを単一の統一された形式に変換するPythonスクリプトがあります。
このPythonスクリプトは遅く、CPUバウンド(マルチコアマシンのシングルコア)なので、データ型ごとに1つずつ)、3つのインスタンスを実行してそれらを組み合わせます。 sort
に渡すための出力。基本的に、これと同等です。
{ ./handle_1.py; ./handle_2.py; ./handle_3.py } | sort -n
しかし、3つのスクリプトが並行して実行されています。
この質問 ここでGNU split
は、ストリームを処理するスクリプトのn個のインスタンス間でいくつかのstdoutストリームをラウンドロビンするために使用されていました。
分割されたmanページから:
-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
したがって、r/N
コマンドは、「行を分割せずに」を意味します。
これに基づいて、次の解決策が実行可能であるように思われます。
split -n r/3 -u --filter="./choose_script" << EOF
> 1
> 2
> 3
> EOF
choose_script
がこれを行う場所:
#!/bin/bash
{ read x; ./handle_$x.py; }
残念ながら、行が混ざり合っているのがわかります。また、そこにあるべきではない改行がたくさんあります。
たとえば、Pythonスクリプトを、これを行ういくつかの単純なbashスクリプトに置き換えると、次のようになります。
#!/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;
私はこの出力を見ます:
1-8394
2-11238
2-22757
1-723
2-6669
3-3690
2-892
2-312511-24152
2-9317
3-5981
これは煩わしいです-上に貼り付けたマニュアルページの抜粋に基づくと、行の整合性を維持するはずです。
明らかに、-u
引数を削除すると機能しますが、その後バッファリングされ、1つを除くすべてのスクリプトの出力をバッファリングするため、メモリが不足します。
誰かがここでいくつかの洞察を持っているなら、それは大いにありがたいです。私はここで私の深さを超えています。
GNU parallelの-uオプションを使用してみてください。
echo "1\n2\n3" | parallel -u -IX ./handle_X.sh
これにより、プロセス全体をバッファリングすることなく、それらを並行して実行します。
試してみてください:
parallel ::: ./handle_1.py ./handle_2.py ./handle_3.py
handle_1.py
がファイル名をとる場合:
parallel ::: ./handle_1.py ./handle_2.py ./handle_3.py ::: files*
出力を混合したくないので、-uを使用しないでください。
順序を維持したい場合(したがって、すべてのhandle_1出力はhandle_2の前にあるため、ソートを回避できる可能性があります):
parallel -k ::: ./handle_1.py ./handle_2.py ./handle_3.py ::: files*
それでもソートしたい場合は、ソートを並列化してsort -m
を利用できます。
parallel --files "./handle_{1}.py {2} | sort -n" ::: 1 2 3 ::: files* | parallel -j1 -X sort -m
$ TMPDIRを、出力を保持するのに十分な大きさのディレクトリに設定します。
多分私は何かが足りないのですが、あなたはただすることができません:
(./handle_1.py & ./handle_2.py & ./handle_3.py) | sort -n
各プロセスの行がインターリーブされないようにする場合は、プロセス自体がそれらを完全に書き込むようにし、パイプへのwrite
sがアトミックであることが保証されているため、出力バッファリングを無効にする方が簡単です。 PIPE_BUF
。たとえば、次のことを確認できますdoes出力バッファリングàlastdio
を使用し、1行または数行が書き込まれた後、fflush
またはpython
にある同等のものを呼び出します。
pythonスクリプトを変更できない場合は、次のことができます。
lb() { grep --line-buffered '^'; }
(with GNU grep)または:
lb() while IFS= read -r l; do printf '%s\n' "$l"; done
(コマンドの出力がテキストでない場合は、以下のコメントの注を参照してください)
そして、やります:
(./handle_1.py | lb & ./handle_2.py | lb & ./handle_3.py | lb) | sort -n
これらの3つのlb
プロセスを回避する別のオプションは、select
/poll
を使用する1つのコマンドへの3つのパイプを使用して、出力の送信元を確認し、それをsort
行ベースにフィードすることですが、プログラミングが少し必要です。
Flowbokの答えは正しい解決策でした。奇妙なことに、GNU parallel
の出力は、ファイルに直接出力される場合はマングルされますが、ttyに送られる場合はマングルされません。
幸運なことに、 script -c
はttyを模倣するために利用できます。
まだ3つのスクリプトがあります:
#!/bin/bash
# handle_1.sh
while true; do echo "1-$RANDOM$RANDOM$RANDOM$RANDOM"; done
。
#!/bin/bash
# handle_2.sh
while true; do echo "2-$RANDOM$RANDOM$RANDOM$RANDOM"; done
。
#!/bin/bash
# handle_3.sh
while true; do echo "3-$RANDOM$RANDOM$RANDOM$RANDOM"; done
次に、並列への呼び出しをカプセル化するファイルがあります。
#!/bin/bash
# run_parallel.sh
parallel -u -I N ./handle_N.sh ::: "1" "2" "3"
そして、私はそれを次のように呼びます:
script -c ./run_parallel > output
出力の行は、異なるスクリプトの出力間で行ごとに混合されますが、特定の行でマングルされたりインターリーブされたりすることはありません。
parallel
からの奇妙な動作-バグレポートを提出する場合があります。