C++ endl は、'\n' の後にフラッシュを出力するように定義されています。 flush() はコストのかかる操作であるため、一般的に endl をデフォルトの行末として使用することは避けるべきです。これは、見ているパフォーマンスの問題を正確に引き起こす可能性があるためです (SMB だけでなく、ローカル スピニングを含む高価なフラッシュを伴うすべての ofstream で発生する可能性があります)。サビや最新の NVMe でさえ、途方もなく高い出力レートで)。
endl を「\n」に置き換えると、システムが意図したとおりにバッファできるようになり、上記のパフォーマンスが修正されます。一部のライブラリを除いて、「\ n」でフラッシュする可能性があります。その場合、さらに頭痛の種になります(sync()メソッドをオーバーライドするソリューションについては、https://stackoverflow.com/questions/21129162/tell-endl-not-to-flushを参照してください) ).
さらに複雑なことに、flush() はライブラリ バッファ内で発生することに対してのみ定義されています。オペレーティング システム、ディスク、およびその他の外部バッファに対するフラッシュの効果は定義されていません。 Microsoft.NET の場合「FileStream.Flush メソッドを呼び出すと、オペレーティング システムの I/O バッファもフラッシュされます。」 (https://msdn.microsoft.com/en-us/library/2bw4h516(v=vs.110).aspx) これにより、フラッシュは Visual Studio C++ で特にコストがかかります。ご覧のとおり、リモート サーバーの遠端にある物理メディアです。一方、GCC は次のように述べています。 ." (https://gcc.gnu.org/onlinedocs/libstdc++/manual/streambufs.html) Ubuntu トレースは、オペレーティング システム/ネットワーク バッファーがライブラリー flush() によってフラッシュされていないことを示しているようです。システムに依存する動作は、endl と過剰なフラッシュを避けるためのより一層の理由になります。 VC++ を使用している場合は、Windows GCC の派生物に切り替えて、システム依存の動作がどのように反応するかを確認するか、Wine を使用して Ubuntu で Windows 実行可能ファイルを実行してみてください。
より一般的には、すべての行をフラッシュすることが適切かどうかを判断するために、要件について考える必要があります。 endl は通常、ディスプレイなどのインタラクティブなストリームに適しています (バーストではなく、ユーザーが実際に出力を確認する必要があります) が、フラッシュのオーバーヘッドが大きくなる可能性があるファイルなど、他のタイプのストリームには一般的に適していません。私はアプリが 1 バイトと 2 バイト、4 バイトと 8 バイトの書き込みごとにフラッシュするのを見てきました... OS が 1MB のファイルを書き込むために何百万もの IO を処理するのは見栄えがよくありません。
たとえば、クラッシュをデバッグしている場合、クラッシュが発生する前に ofstream をフラッシュする必要があるため、ログ ファイルのすべての行をフラッシュする必要がある場合があります。一方、別のログ ファイルは、アプリケーションが終了する前に自動的にフラッシュされると予想される詳細な情報ログを生成するだけの場合、すべての行をフラッシュする必要はありません。特定の要件に合わせて、より洗練されたフラッシュ アルゴリズムを使用してクラスを派生させることができるので、そのどちらかである必要はありません。
あなたのケースを、データがディスクに完全に永続化され、オペレーティング システム バッファーで脆弱でないことを確認する必要がある対照的なケースと比較してください (https://stackoverflow.com/questions/7522479/how-do-i-ensure-data -is-write-to-disk-before-closed-fstream).
書かれているように、 outFile.flush() は不要であることに注意してください。これは、すでにフラッシュされたオフストリームをフラッシュするためです。分かりやすく説明すると、endl を単独で使用するか、できれば "\n" を outFile.flush() と共に使用する必要がありますが、両方を使用する必要はありません。
SMB プロトコルを使用した読み取り/書き込みなどのリモート ファイル操作のパフォーマンスは、サーバーとクライアントによって割り当てられたバッファーのサイズの影響を受ける可能性があります。バッファー サイズは、一定量のデータを送信するために必要なラウンド トリップの数を決定します。要求と応答がクライアントとサーバー間で送信されるたびに、かかる時間は、少なくとも両側間の待ち時間に等しくなります。これは、ワイド エリア ネットワーク (WAN) の場合には非常に重要になる可能性があります。
SMB バッファ -- MaxBufferSize は、次のレジストリ設定で構成できます:
HKLM\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters\SizeReqBuf
データ型:REG_DWORD
範囲:1024 から 65535 (5000 を超える値は要件に応じて選択してください)
ただし、SMB SIGNING は、許可される最大バッファー サイズに影響します。したがって、目標を達成するには、SMB 署名も無効にする必要があります。次のレジストリは、サーバー側と、可能であればクライアント側の両方で作成する必要があります。
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\LanManWorkstation\Parameters
値の名前:EnableSecuritySignature
データ型:REG_DWORD
データ:0 (無効)、1 (有効)
コメントを残すのに十分な評判がありません(この回答の検証レベルを考えると、より良いと思います)。
Linux と Windows レベルのトレースの大きな違いの 1 つは、Linux で SMB1 を使用し、Windows で SMB2 を使用していることです。おそらく、バッチ oplock メカニズムは、SMB2 の排他的リースの実装よりも SMB1 samba の方が優れたパフォーマンスを発揮します。どちらの場合も、クライアント側のキャッシュをある程度許可する必要があります。
1) おそらく、Samba で最大プロトコル レベルを低く設定して、SMB で Windows を試してみてください12) 排他的 oplock またはリースが取得されていることを検証します
これが役立つことを願っています:)