2

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/63process_fileprocess_file

特にディスクに触れること (パフォーマンス) と、処理後に一時ファイルをクリーンアップ (削除) する必要があることに関して、一時ファイルの作成を避けたかったのです。この問題があると、それが妨げられます。置換されたプロセス パイプラインの疑似ファイルの名前にある種の競合状態があるかどうか、私は興味がありますか? それとも、私が誤解しているように見えるプロセスの代替またはジョブ制御について何かありますか?

参考までに、Ubuntu Server 14.04、linux 3.19.0-59 Bash 4.3.11 gzip 1.6 を使用しています。

4

1 に答える 1

1

少し掘り下げたので、正しい方向に向けることができるかもしれません。

どうやら /dev/fd/63 は、process_file で使用される標準のファイル記述子です。したがって、process_file の複数のインスタンスを実行すると、このファイル記述子を介してすべてを送信しようとします。ご想像のとおり、競合または競合状態が発生している可能性があります。

このページファイル記述子と bash シェル スクリプト、およびこのページredirection_tutorial には、出力のリダイレクトの例があります。

一意のファイル記述子を作成するか、使用中の記述子をロックするには、おそらく process_file を変更する必要があります。

于 2016-07-02T00:22:38.880 に答える