3秒ごとに既存のファイルに新しい行を追加するPerlスクリプトがあります。また、そのファイルから読み取るC++アプリケーションもあります。
問題は、スクリプトが完了してファイルハンドルが閉じられた後、アプリケーションがファイルの読み取りを開始することです。これを回避するために、各行の追加後にフラッシュしたいと思います。どうやってやるの?
3秒ごとに既存のファイルに新しい行を追加するPerlスクリプトがあります。また、そのファイルから読み取るC++アプリケーションもあります。
問題は、スクリプトが完了してファイルハンドルが閉じられた後、アプリケーションがファイルの読み取りを開始することです。これを回避するために、各行の追加後にフラッシュしたいと思います。どうやってやるの?
試す:
use IO::Handle;
$fh->autoflush;
これは、これを達成するための広く受け入れられている悪い方法について尋ねた私の初期の質問で、自動フラッシュの方法として実際に投稿されました:-)
TL/DR: 用途IO::Handle
とflush
方法、例:
use IO::Handle;
$myfile->flush();
まず、どの程度「フラッシュ」するかを決定する必要があります。かなりの数のバッファリング層が存在する可能性があります:
ファイル ハンドルの Perl の内部バッファ。他のプログラムは、このバッファを離れるまでデータを見ることができません。
「ダーティ」ファイル ブロックのファイル システム レベルのバッファリング。他のプログラムはこれらの変更を引き続き見ることができ、「書き込まれた」ように見えますが、OS またはマシンがクラッシュすると失われます。
書き込みのディスク レベルのライトバック バッファリング。OSはこれらがディスクに書き込まれていると考えていますが、実際にはディスクはドライブの揮発性メモリにそれらを保存しているだけです. OS がクラッシュしてもデータが失われることはありませんが、電源が落ちた場合は、ディスクが最初にデータを書き出せない限り失われる可能性があります。これは、安価な消費者向け SSD の大きな問題です。
SAN、リモート ファイル システム、RAID コントローラなどが関与すると、さらに複雑になります。パイプ経由で書き込んでいる場合は、考慮すべきパイプ バッファもあります。
Perl バッファをフラッシュするだけの場合は、 (Perl は改行でフラッシュするように見えるため)を含む文字列close
のファイルを使用するか、のmethodを使用できます。print
"\n"
IO::Handle
flush
また、 perl のよくある質問に従って、ファイル ハンドルをバッファリングしないようにすることもできbinmode
ます。$|
これは、バッファリングされたハンドルをフラッシュすることと同じではありません。バッファリングされた一連の書き込みをキューに入れ、単一のフラッシュを実行すると、バッファリングされていないハンドルに書き込むよりもパフォーマンス コストがはるかに低くなるからです。
ファイル システムのライト バック バッファをフラッシュしたい場合は、 のようなシステム コールを使用するか、ファイルをモードでfsync()
開くか、他の多数のオプションのいずれかを使用する必要があります。PostgreSQL にはファイル同期方法をテストするためだけの独自のツールがO_DATASYNC
あるという事実からも明らかなように、これは非常に複雑です。
永久ストレージのハード ドライブに本当に、本当に、正直にあることを確認したい場合は、プログラムのファイル システムにフラッシュする必要があります。OSが要求したときに実際にフラッシュするように、ハードドライブ/ SSD / RAIDコントローラー/ SANなどを構成する必要もあります。これを行うのは驚くほど複雑になる可能性があり、OS/ハードウェアに固有です。本当に正しいことを確認するために、「プラグプル」テストを強くお勧めします。
'man perlfaq5'から:
$old_fh = select(OUTPUT_HANDLE);
$| = 1;
select($old_fh);
stdoutをフラッシュしたいだけの場合は、おそらく次のようにすることができます。
$| = 1;
ただし、のような使いやすい抽象化を提供するモジュールの詳細については、FAQを確認してくださいIO::Handle
。
自動フラッシュの設定を提案するすべてのソリューションは、Perlが何をしているかに関係なく、ほとんどの最新のOSがファイルI/Oをバッファリングしているという基本的な事実を無視しています。
データのディスクへのコミットを強制する唯一の可能性は、ファイルを閉じることです。
書き込まれるログのローテーションに問題があるのと同じジレンマATMに閉じ込められています。
PerlDocにこれに関する記事があります:出力ファイルハンドルをフラッシュ/バッファリング解除するにはどうすればよいですか?なぜ私はこれをしなければならないのですか?
2つの解決策:
$|
IO::Handle
またはそのサブクラスの1つを使用している場合は、autoflushメソッドを呼び出します。出力を自動的にフラッシュするには、ファイルハンドルに出力する前に$|
、他の人が説明したようにautoflush/ を設定できます。
すでにファイルハンドルに出力しており、それが物理ファイルに到達することを確認する必要がある場合は、IO::Handleflush
とsync
メソッドを使用する必要があります。
別のアプローチは、現在使用しているファイルの代わりに、PerlスクリプトとC++プログラムの間に名前付きパイプを使用することです。