3

Windows アプリケーションには、ファイル名とバッファをラップするクラスがあります。ファイル名でそれを構築し、オブジェクトをクエリして、バッファがまだいっぱいかどうかを確認できます。そうでない場合は nullptr を返し、そうである場合はバッファ アドレスを返します。オブジェクトがスコープ外になると、バッファが解放されます。

class file_buffer
{
public:
    file_buffer(const std::string& file_name);
    ~file_buffer();
    void* buffer();

private:
    ...
}

データを非同期的にメモリに入れたいのですが、私が見る限り、2 つの選択肢があります。バッファを作成して ReadFileEx を介してオーバーラップ IO を使用するか、MapViewOfFile を使用して別のスレッドのアドレスにアクセスします。

現時点では、約 16MB を超えるリクエストは失敗する傾向があるため、いくつかの問題を提示する ReadFileEx を使用しています。バッファ クリーンアップの問題があります。また、クラスの複数のインスタンスが立て続けに作成されると、非常に面倒になります。

上限の問題がないため、別のスレッドでのデータのマッピングとタッチはかなり簡単に思えます。また、クライアントが今すぐデータを絶対に取得する必要がある場合は、単にアドレスを逆参照して、OS に心配させることができます。ページ フォールトが発生し、ブロッキング ヒットが発生します。

このアプリケーションはシングル コア マシンをサポートする必要があるため、私の質問は次のとおりです。別のソフトウェア スレッドでのページ フォールトは、現在のスレッドでのオーバーラップ IO よりも高くつくのでしょうか? 彼らはプロセスを停止しますか?オーバーラップした IO は同じようにプロセスを停止させますか、それとも私が理解できない OS マジックがありますか? ページ フォールトはオーバーラップ IO を使用して実行されますか?

私は次のトピックをよく読んで ます 。 microsoft.com/en-us/library/windows/desktop/aa366556(v=vs.85).aspx (ファイル マッピング) しかし、パフォーマンスのトレードオフを行う方法を推測できないようです。

4

2 に答える 2

14

間違いなく、メモリ マップト ファイルを使いたくなるでしょう。オーバーラップされた IO ( with FILE_FLAG_NO_BUFFERING) は、何年もの間、「RAM にデータを取得する最速の方法」として提唱されてきましたが、これは、非常に特殊な条件で非常に不自然な場合にのみ当てはまります。通常の平均的なケースでは、バッファ キャッシュをオフにすることは深刻な最適化の妨げになります。

現在、オーバーラップされた IOなし FILE_FLAG_NO_BUFFERINGには、オーバーラップされた IOの癖がすべてあり、約 50% 遅くなります (理由はまだ理解できません)。

1年前にかなり大規模なベンチマークを実施しました。要するに、メモリ マップされたファイルはより速く、より優れており、それほど驚くべきことではありません。

オーバーラップした IO はより多くの CPU を使用し、バッファー キャッシュを使用すると非常に遅くなり、十分に文書化された条件と文書化されていない条件 (暗号化、圧縮、および... 純粋な偶然? 要求サイズ? 要求数?) では、非同期は同期に戻ります。予期しない時間にアプリケーションを停止させます。
リクエストの送信には「おかしな」時間がかかるCancelIO場合があり、何もキャンセルせずに完了するのを待つ場合もあります。未処理のリクエストがあるプロセスは強制終了できません。未解決のオーバーラップ書き込みのあるバッファを管理することは、重要な余分な作業です。

ファイルマッピングは機能します。フルストップ。そして、それはうまく機能します。驚きも、面白いこともありません。すべてのページにアクセスしても、オーバーヘッドはほとんどなく、ディスクが配信できるのと同じ速さで配信され、バッファー キャッシュを利用します。シングルコア CPU に関する懸念は問題ありません。タッチ スレッドに障害が発生するとブロックされ、スレッドがブロックされると、いつものように別のスレッドが代わりに CPU 時間を取得します。

書き込むバイトが数バイトを超える場合はいつでも、書き込みにファイル マッピングを使用しています。これはやや簡単ではありません (ファイルとマッピングを手動で拡大/事前割り当てし、閉じるときに実際の長さに切り詰める必要があります) が、一部のヘルパー クラスでは完全に実行可能です。500 MiB のデータを書き込み、「ゼロ時間」かかります (基本的に を実行しますmemcpy。実際の書き込みは、プログラムが終了した後でもバックグラウンドで行われます)。オペレーティング システムにとって当然のことだとわかっていても、これがうまく機能するのは驚くべきことです。
もちろん、OS がすべてのページを書き出す前に電源障害が発生しないようにする必要がありますが、それはあらゆる種類の書き込みに当てはまります。ディスクにないものはまだディスクにない-- それ以上に言うべきことは本当にありません。それを確認する必要がある場合は、ディスクの同期が完了するまで待つ必要があります。それでも、同期を待っている間、ライトが消えていないことを確認することはできません。それが人生だ。

于 2013-03-04T12:03:44.667 に答える
4

あなたが何らかの調査を行ったように見えるので、私はあなたよりもこれをよく理解しているとは言いません。そして、完全に確実にするために、あなたは実験する必要があるでしょう。しかし、これは逆の順序で問題についての私の理解です。

  1. WindowsでのファイルマッピングとオーバーラップIOは異なる意味合いであり、内部で他に依存するものはありません。ただし、どちらも非同期ブロックデバイスレイヤーを使用します。私が想像しているように、カーネルではすべてのIOは実際には非同期ですが、一部のユーザー操作はそれが終了するのを待つため、同期性の錯覚を引き起こします。
  2. ポイント1から、スレッドがIOを実行する場合、同じプロセスの他のスレッドはストールしません。つまり、システムリソースが不足していない限り、またはこれらの他のスレッドがIO自体を実行し、ある種の競合に直面している場合を除きます。これは、最初のスレッドが実行するIOの種類(ブロッキング、非ブロッキング、オーバーラップ、メモリマップ)に関係なく当てはまります。
  3. メモリマップトファイルでは、データは一度に少なくとも1ページずつ読み取られます。おそらく先読みのためですが、それについては確信が持てません。したがって、プロービングスレッドは、すべてのページで少なくとも1つはマップされたメモリにアクセスする必要があります。これは、probe / block-probe-probe-probe-probe / block-probeのようなものになります...これは、数MBの大きなオーバーラップ読み取りよりも少し効率が悪い可能性があります。あるいは、カーネルプログラマーは賢く、さらに効率的かもしれません。少しプロファイリングを行う必要があります...ねえ、プロービングスレッドなしで行って、何が起こるかを確認することもできます。
  4. 重複する操作をキャンセルするのはPITAなので、メモリマップトファイルを使用することをお勧めします。これはセットアップがはるかに簡単で、追加の機能を利用できます。
    1. メモリが完全にメモリに入る前でも使用可能
    2. メモリは、プロセスの複数のインスタンスで共有できます/共有されます
    3. メモリがキャッシュ内にある場合は、すぐにではなく、即座に準備が整います。
    4. データが読み取り専用の場合は、メモリを書き込みから保護してバグを検出できます。
于 2013-03-04T10:01:10.407 に答える