2016-07-01 2 views
2

20MiBのCSVファイルのバッチを処理するスクリプトがあります。必要に応じてgzip圧縮して、約4MiBまで圧縮できます。何千ものファイルがあり、処理にはそれぞれ約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で処理されると報告されたファイルは、process_fileの別々の同時インスタンスであっても、常に/dev/fd/63と報告されています。一方、ファイルを一時的にコピーまたは解凍し、一時ファイルの名前をprocess_fileに渡すと、正常に実行され、すべてのファイルが正しく処理されているように見えます。

一時ファイルを作成することは避けたかったが、特にディスクに触れること(パフォーマンス)や、処理後に一時ファイルをクリーンアップ(削除)する必要があった。この問題を抱えていることはそれを妨げる。だから私は、代替プロセスパイプラインの疑似ファイル名に何らかの競合条件があるのではないかと不思議です。それとも、私が誤解しているようなプロセスの置き換えや仕事のコントロールについて何かありますか?

参考

、私は のUbuntu Serverの14.04、Linuxの3.19.0-59 バッシュ4.3.11 のgzip 1.6

答えて

1

を使用している私は掘るのビットを行なったし、右であなたを指すことができるかもしれません方向。

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

このページfile descriptors and bash shell scriptingとこのページredirection_tutorialには、出力のリダイレクトに関する例があります。

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

+0

私の理解から、ファイル記述子はBashによって作成されていますが – inetknght