1

あなたが持っているかもしれないし持っていないかもしれないいくつかのライブラリを使って、私は大まかにこのようなPythonコードをいくつか持っています:

# Open it for writing
vcf_file = open(local_filename, "w")

# Download the region to the file.
subprocess.check_call(["bcftools", "view",
    options.truth_url.format(sample_name), "-r",
    "{}:{}-{}".format(ref_name, ref_start, ref_end)], stdout=vcf_file)

# Close parent process's copy of the file object
vcf_file.close()

# Upload it
file_id = job.fileStore.writeGlobalFile(local_filename)

基本的に、データをダウンロードして標準出力に出力するサブプロセスを開始しています。そのデータをファイルにリダイレクトし、サブプロセス呼び出しが戻るとすぐに、ファイルへのハンドルを閉じて、ファイルを別の場所にコピーします。

私が期待しているデータの最後尾がコピーに含まれていない場合があることを観察しています。今、時々そのデータを書き込んでいない可能性がありますが、安全でないことをしていて、が戻った後、子プロセスが標準出力に書き込むデータが作成される前にbcftools、何らかの方法でファイルにアクセスできるのではないかと心配しています。私が見ることができるディスクに。subprocess.check_call()

C 標準を見ると (bcftools は C/C++ で実装されているため)、プログラムが正常に終了すると、開いているすべてのストリーム (標準出力を含む) がフラッシュされて閉じられるように見えます。戻り時に暗黙的に呼び出されるの動作について説明している、こちら[lib.support.start.term]のセクションを参照してください。exit()main()

--次に、未書き込みのバッファリングされたデータを含むすべての開いている C ストリーム (で宣言されている関数シグネチャによって仲介される) がフラッシュされ、開いているすべての C ストリームが閉じられ、tmp-file() の呼び出しによって作成されたすべてのファイルが削除されます.30)

-- 最後に、制御がホスト環境に戻されます。status が 0 または EXIT_SUCCESS の場合、成功した終了ステータスの実装定義形式が返されます。ステータスが EXIT_FAILURE の場合、ステータスの失敗した終了の実装定義形式が返されます。それ以外の場合、返されるステータスは実装定義です.31)

したがって、子プロセスが終了する前に、標準出力を閉じます (したがって、フラッシュします)。

ただし、Linuxのマニュアル ページclose(2)では、ファイル記述子を閉じても、それに書き込まれたデータが実際にディスクに書き込まれたことを必ずしも保証しないことに注意してください。

カーネルが書き込みを遅延させるため、クローズが成功しても、データがディスクに正常に保存されたことは保証されません。ストリームが閉じられたときにファイルシステムがバッファをフラッシュすることは一般的ではありません。データが物理的に保存されていることを確認する必要がある場合は、fsync(2) を使用してください。(この時点では、ディスク ハードウェアによって異なります。)

したがって、プロセスが終了すると、その標準出力ストリームがフラッシュされるように見えますが、そのストリームがディスク上のファイルを指すファイル記述子によって実際にバックアップされている場合、ディスクへの書き込みが完了したとは限りません。それがここで起こっていることかもしれないと思います。

だから、私の実際の質問:

  1. 私の仕様の読みは正しいですか?リダイレクトされた標準出力がディスク上で利用可能になる前に、子プロセスが親に終了したように見えることがありますか?

  2. 子プロセスによってファイルに書き込まれたすべてのデータが実際に OS によってディスクに同期されるまで、何らかの方法で待機することは可能ですか?

  3. 親プロセスのファイルオブジェクトのコピーで、flush()またはPythonバージョンを呼び出す必要がありますか? fsync()子プロセスによる同じファイル記述子への書き込みを強制的にディスクにコミットできますか?

4

1 に答える 1

1

はい、データがディスクに (物理的に) 書き込まれるまでに数分かかる場合があります。しかし、それよりずっと前に読むことができます。

電源障害やカーネル パニックを心配している場合を除きます。データがディスク上にあるかどうかは問題ではありません。カーネルがデータが書き込まれたと考えるかどうかが重要な部分です。

check_call()返されたらすぐにファイルから読み取っても安全です。すべてのデータが表示されない場合。バグを示しているbcftoolswriteGlobalFile()、ファイルからすべてのデータをアップロードしていない可能性があります。bsftoolsstdoutのブロック バッファリング モードを無効にすることで、前者の回避策を試すことができます(疑似 tty を提供する、unbufferコマンド ライン ユーティリティを使用するなど)。

Q:仕様の読み方は正しいですか? リダイレクトされた標準出力がディスク上で利用可能になる前に、子プロセスが親に終了したように見えることがありますか?

はい。はい。

Q:子プロセスによってファイルに書き込まれたすべてのデータが OS によって実際にディスクに同期されるまで、何らかの方法で待機することは可能ですか?

番号。fsync()一般的なケースでは十分ではありません。いずれにせよ必要ない可能性があります (データを読み戻すことは、データがディスクに書き込まれることを確認することとは別の問題です)。

Q:親プロセスのファイル オブジェクトのコピーに対して、flush() または Python バージョンの fsync() を呼び出す必要がありますか? 子プロセスによる同じファイル記述子への書き込みを強制的にディスクにコミットできますか?

それは無意味です。.flush()親プロセスの内部にあるバッファーをフラッシュします (親プロセスにopen(filename, 'wb', 0)不要なバッファーを作成しないようにするために使用できます)。

fsync()ファイル記述子で動作します (子には独自のファイル記述子があります)。カーネルが、同じディスク ファイルを参照する異なるファイル記述子に対して異なるバッファを使用するかどうかはわかりません。繰り返しますが、データが欠落している (クラッシュしていない) 場合は問題ありません。fsync()ここでは役に立ちません。

Q:明確にするために、関連する OS バッファーがプロセス間で共有されているため、データは実際に他のプロセスによって読み取り可能である必要があると主張しているように見えます。しかし、その主張のソースは何ですか? これらのバッファが共有されていることを保証することを指摘できる仕様または Linux ドキュメントの場所はありますか?

「通常のファイルに正常に戻った後」をwrite()探します。

read()その書き込みによって変更されたファイル内の各バイト位置からの成功はwrite() 、そのようなバイト位置が再び変更されるまで、その位置に対して によって指定されたデータを返します。

于 2016-01-06T05:35:30.033 に答える