20MiB の CSV ファイルのバッチを処理するスクリプトがあり、オプションで約 4MiB まで gzip 圧縮されています。何千ものファイルがあり、それぞれの処理には約 30 秒かかります。非圧縮ファイルまたは圧縮ファイルの読み取りと解凍は「ほぼ瞬時」であり、プロセスがプロセスレベルで並列化できることを強く示唆しています。実際、それは複雑な Ruby パイプラインを使用して行われていることです。ただし、bash を使用して Ruby コードをより小さな部分に分割しようとしています。ジョブ制御のために、私はこのbash関数を考え出しました
wait_until_job_available() {
maximum_jobs=${MAXIMUM_JOBS}
[ $# -eq 0 ] || maximum_jobs="${1}"
exit_status=0
RUNNING_JOBS=( $(jobs -p) )
while [ ${maximum_jobs} -le ${#RUNNING_JOBS[@]} ] && [ 0 -eq "${exit_status}" ]
do
# `wait -n` requires bash 4.3 which is unfortunately not available on several recent RHEL-based Linux distributions such as Oracle Linux
wait -n
exit_status=$?
RUNNING_JOBS=( $(jobs -p) )
done
return ${exit_status}
}
wait_until_job_available
これにより、bash パイプラインをバックグラウンド化する前に、実行可能なジョブの最小数をオプションで指定して を呼び出すことができます(省略した場合は、マシンで使用可能なコアの数がデフォルトになります)。
だから私はそれを次のように使うかもしれません:
while read file
do
CAT_COMMAND=cat
# if input file is gzip-compressed, pipe zcat instead of cat
if [ "${INFILE: -3}" == ".gz" ]
then
CAT_COMMAND=zcat
fi
# wait for a job to become available
wait_until_job_available
# read the uncompressed file, write processed data to file.out
process_file -i <(${CAT_COMMAND} ${file}) -o ${file}.out &
# while searching for filesystem paths of type _f_ile
done < <(find ${search_path} -type f)
# wait for all background jobs to finish
wait
ご覧のとおり、これによりすべてのファイルが検索search_path
され、コマンドに渡されますprocess_file
。その際、私はプロセス置換を使用してファイルを cat するか、オンザフライでファイルを解凍します。入力ファイル名は、圧縮されていないファイルの内容を出力するプロセスに置き換えられ、出力ファイルは元のファイル名に「.out」が追加されたものになります。の呼び出しprocess_file
はバックグラウンド化され、ジョブ コントロールに送信されます。ダンディーに見えますよね?
ただし、一部のファイルが正しく処理されていないことに気付きました。
によって処理されると報告されたファイルは、 の別々の同時インスタンスであっても、process_file
常に であると報告されることに気付きました。一方、ファイルを一時ファイルに個別にコピーまたは解凍し、一時ファイルの名前を に渡すと、正常に実行され、すべてのファイルが正しく処理されているように見えます。/dev/fd/63
process_file
process_file
特にディスクに触れること (パフォーマンス) と、処理後に一時ファイルをクリーンアップ (削除) する必要があることに関して、一時ファイルの作成を避けたかったのです。この問題があると、それが妨げられます。置換されたプロセス パイプラインの疑似ファイルの名前にある種の競合状態があるかどうか、私は興味がありますか? それとも、私が誤解しているように見えるプロセスの代替またはジョブ制御について何かありますか?
参考までに、Ubuntu Server 14.04、linux 3.19.0-59 Bash 4.3.11 gzip 1.6 を使用しています。