7

コンパイラ、オプティマイザ、およびインデックス作成テクノロジについて詳しく知るために、C#でおもちゃのデータベースを構築しています。

ページをバッファプールに取り込むための(少なくとも読み取り)要求間で最大の並列処理を維持したいのですが、.NETでこれを実現するための最善の方法について混乱しています。

ここにいくつかのオプションと私がそれぞれに遭遇した問題があります:

  1. 使用法System.IO.FileStreamBeginRead方法

    ただし、ファイル内の位置はの引数ではなく、(メソッドを介して設定された)BeginReadのプロパティであるため、一度に1つのリクエストしか発行できず、その間ストリームをロックする必要があります。(または、私は?との間にのみロックを保持し、電話をかける前にロックを解除した場合、ドキュメントは不明確です。誰か知っていますか?)これを行う方法を知っていますが、それが最良の方法。FileStreamSeekSeekBeginReadEndRead

  2. 構造とkernel32.dllSystem.Threading.Overlappedの関数へのP\Invokeを 中心とした別の方法があるようです。ReadFileEx

    残念ながら、特に管理された言語では、サンプルが不足しています。このルート(動作させることができる場合)にはThreadPool.BindHandle、スレッドプール内のメソッドとIO完了スレッドも含まれているようです。これがウィンドウの下でこのシナリオを処理するための認可された方法であるという印象を受けますが、私はそれを理解しておらず、初心者に役立つドキュメントへのエントリポイントを見つけることができません。

  3. 他に何かありますか?

  4. コメントの中で、jacobはFileStream、飛行中の読み取りごとに新しいものを作成することを提案しています。

  5. ファイル全体をメモリに読み込みます。

    これは、データベースが小さい場合に機能します。コードベースは小さく、他にも多くの非効率性がありますが、データベース自体はそうではありません。また、大規模なデータベース(ページング、外部ソーティングなど、複雑さの大部分を占めることが判明)を処理するために必要なすべての簿記を確実に実行していることを確認したいと思います。誤ってごまかしやすい。

編集

解決策1に疑問がある理由の明確化:BeginReadからEndReadまでずっと単一のロックを保持するということは、別の読み取りが進行中であるという理由だけで読み取りを開始したい人をブロックする必要があることを意味します。新しい読み取りを開始するスレッドは、結果が利用可能になる前に(一般に)さらにいくつかの作業を実行できる可能性があるため、これは間違っていると感じます。(実際、これを書くだけで、新しい解決策を考えるようになりました。私は新しい答えとして置きました。)

4

4 に答える 4

5

オプション1がうまくいかない理由がわかりません。2つの異なるスレッドが同じFileStreamを同時に使用しようとすることはできないことに注意してください。そうすると、間違いなく問題が発生します。BeginRead / EndReadは、ファイルへのある種のマルチスレッドアクセスを有効にするのではなく、潜在的にコストのかかるIO操作が行われている間もコードの実行を継続できるようにすることを目的としています。

だから私はあなたがシークしてからbeginreadをすることをお勧めします。

于 2008-09-18T00:48:58.857 に答える
3

私たちが行ったのは、C ++/CLIでI/O完了ポート、ReadFile、およびGetQueuedCompletionステータスの周りに小さなレイヤーを記述し、操作が完了したときにC#にコールバックすることでした。ファイル(またはソケット)からの読み取りに使用されるバッファーをより細かく制御できるように、BeginReadおよびc#非同期操作パターンではなくこのルートを選択しました。これは、読み取りごとにヒープに新しいbyte[]を割り当てる純粋に管理されたアプローチよりもかなり大きなパフォーマンスの向上でした。

さらに、インターウェブ上でIO完了ポートを使用するより完全なC++の例がたくさんあります。

于 2008-09-18T01:27:41.480 に答える
1

最初にリソース(ファイルデータなど)をメモリにロードしてから、スレッド間で共有した場合はどうなりますか?小さなデータベースなので。-対処すべき問題はそれほど多くありません。

于 2008-09-18T00:52:14.700 に答える
0

アプローチ#1を使用しますが、

  1. 要求が入ってきたら、ロック A を取得します。これを使用して、保留中の読み取り要求のキューを保護します。それをキューに追加し、新しい非同期結果を返します。これがキューへの最初の追加になる場合は、戻る前に手順 2 を呼び出します。戻る前にロック A を解除します。

  2. 読み取りが完了する (または手順 1 で呼び出される) と、ロック A を取得します。これを使用して、キューからの読み取り要求のポップを保護します。Seekロック B を取ります。これを使用して、 -> BeginRead->EndReadシーケンスを保護します。ロック B を解放します。この読み取り操作の手順 1 で作成された非同期の結果を更新します。(読み込みが完了したので、再度呼び出します。)

これにより、別の読み取りが進行中であるという理由だけで読み取りを開始するスレッドをブロックしないという問題が解決されますが、ファイル ストリームの現在の位置が混乱しないように読み取りが順序付けられます。

于 2008-09-18T01:12:55.867 に答える