並列に生成された3つの異なるストリームから単一の出力ストリームを作成する

並列に生成された3つの異なるストリームから単一の出力ストリームを作成する

3種類のデータがあります。各データ型には、それを単一の統合形式に変換するPythonスクリプトがあります。

このPythonスクリプトは遅くてCPUにバインドされているので(マルチコアシステムの単一コアに対して)3つのインスタンス(各データ型ごとに1つ)を実行し、出力を結合しますsort。これは次のとおりです。

{ ./handle_1.py; ./handle_2.py; ./handle_3.py } | sort -n

ただし、3 つのスクリプトは並列に実行されます。

私が見つけたこの問題ここで、GNU は、splitストリームを処理するスクリプトの n インスタンス間で標準出力ストリームを繰り返すために使用されます。

分割マニュアルページから:

-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つを除くすべての出力をバッファリングするため、メモリが不足します。

誰でもここに洞察力があれば大変感謝します。私は深さを超えています。

答え1

GNU並列処理の-uオプションを試してください。

echo "1\n2\n3" | parallel -u -IX ./handle_X.sh

これは、プロセス全体をバッファリングせずに並列に実行します。

答え2

努力する:

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を使用しないでください。

順序を維持したい場合(したがって、すべてのhandler_1出力がhandler_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 を出力を保存するのに十分な大きさのディレクトリに設定します。

答え3

私は何かを逃したかもしれませんが、これはできません。

(./handle_1.py & ./handle_2.py & ./handle_3.py) | sort -n

各プロセス内の行がインターリーブされないようにするには、プロセス自体に行を完全に書き込んで出力バッファリングを無効にする方が簡単ですwrite。パイプPIPE_BUF。たとえば、次のことを保証できます。する出力バッファリングを使用して、1stdio行または複数行、またはfflushそれに対応するコンテンツを作成してから呼び出します。python

Pythonスクリプトを変更できない場合は、次のことができます。

lb() { grep --line-buffered '^'; }

(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もう1つのオプションは、select/を使用するコマンドに3つのパイプを使用してpoll出力がどこから来るかを確認し、それをsortラインベースの出力に供給することです。しかし、ここでは少しのプログラミングが必要です。

答え4

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

出力の行は、異なるスクリプトの出力間で 1 行ずつ混在しますが、与えられた行から切り離されたりインターリーブされたりすることはありません。

奇妙な行動parallel- バグレポートを提出することができます。

関連情報