-2

まず、EndRead のドキュメントでは、BeginReadによって開始された非同期読み取り操作がアトミックまたは中断不可能であると明示的に述べていません。

質問

FileStream.BeginRead によって開始された非同期読み取り操作を中断して、バッファがいっぱいになる前に終了し、これまでにバッファに読み取られたバイト数を返すことは可能ですか?

つまり、「Cancel_IO」のような呼び出し可能なメソッドがあり、EndRead を呼び出すと、可能なすべてのバイトが読み取られるのを待つのではなく、読み取りがキャンセルされた結果として早く返されますか?

バックグラウンド

FileStream、BeginRead、および EndRead のドキュメントを読みました。EndRead には、部分的にいっぱいのバッファーを返し、操作の早期完了をトリガーできるオーバーロードはありません。FileStream.BeginRead によって開始された操作が EndRead のときに早期に終了する可能性がある、Windows オペレーティング システムの API (Win32) またはディスク ドライバー API のメソッドの存在を誰かが確認または拒否できるかどうかに興味があります。呼ばれた。「早期」とは、要求されたバッファー長全体をエラーなしで満たす前を意味します。

使用事例

想像を絶するために、ファイルがネットワーク共有上にあり、ネットワークが極端な速度低下を経験する場合があると仮定すると、一般的な 1MB バッファリング操作の早期完了をトリガーすることが実用的かつ最適です。新しい 1MB バッファリング操作を再開する前に処理するための数バイト。

これらの「数バイト」を使用して、計算集約型の多数のメモリ内リソースの構築を開始できます。これらのリソースは、バッファリングの終了が許可されている間に構築できます。

ドキュメントについて

BeginRead のドキュメントでは、非同期操作がアトミックである、または中断できないことを明示的に述べていないことに注意してください。言及されているのは、「エラー」が発生した場合、EndRead が呼び出されるまでそれについてわからないということだけです。これは、EndRead が要求された数よりも少ないバイト数を返す原因となる、エラーではない他のイベントが発生する可能性を排除するものではありません。

たとえば、「ファイルの終わり」と「バッファがいっぱい」は、非同期読み取り操作の 2 つの「自然な」中断と見なすことができ、エラーなしで、要求されたバイト数よりも少ない数を返します。「人為的な」割り込みの可能性を探しています。これにより、EOF の前でバッファーがいっぱいになる前に、EndRead がバッファーに読み込まれたバイト数を正常に返すことにもなります。

4

3 に答える 3

2

ドキュメントには、次のように明示的に記載されています。読み取られたバイト数を確認するには、このIAsyncResultを使用してEndReadを呼び出す必要があります。一方、EndReadは、読み取り操作が完了するまでスレッドをブロックしています。したがって、読み取り操作はアトミックであるように見えます。

あなたのシナリオには少し実用的な使い方があるので、これは私にとって論理的です。読み取るファイルの一部に貴重な情報が保存されている場合は、いつでも小さな部分で読み取ることができます。

于 2011-08-29T03:41:06.960 に答える
0

Windows の同期および非同期 I/O のドキュメントで、トリックを行う可能性のあるものを読みましたが、結果が不確実なトリックです。

「ハンドルの割り当てが途中で解除された場合、ReadFile または WriteFile は、I/O 操作が完了したと誤って報告する可能性があります。」

.NET BeginRead メソッドは最終的に Win32 ReadFile メソッドに基づいているため、ハンドルを取得して時期尚早に割り当てを解除すると、私がやろうとしていることを達成できる可能性があります。この結果については調査が必要です。

また、「保留中のすべての非同期 I/O 操作をキャンセルするには、 CancelIoまたはCancelIoExのいずれかを使用します」と記載されていますが、これらは操作全体をキャンセルして失敗したように見えます (ERROR_OPERATION_ABORTED)。読み取られたバイトが既にバッファに書き込まれているかどうかはわかりません。また、書き込まれたとしても、何バイトが正常に書き込まれたかはわかりません。基になるシステムをだまして、ファイルまたはストリームの最後に突然到達したと思わせる方法があるのだろうか...

また、「SetCommTimeouts」メソッドには興味深い結果がいくつかあることもわかります。特に、「COMMTIMEOUTS Structure」の「 ReadIntervalTimeout 」メンバーを囲んで、次のように主張しています。

「任意の 2 バイトの到着間隔がこの量を超える場合、ReadFile 操作は完了し、バッファリングされたデータが返されます。」

それは有望に思えます...

いずれにせよ、保留中の非同期 I/O をキャンセルできるという事実だけでも役に立ちます。バッファリングの統計情報と開始時間を使用して、非同期読み取りをキャンセルし、目的のデータ チャンクの小さな読み取りを再発行する価値があるかどうか、または操作が完了するまで待つ方がよいかどうかを実際に計算できました。これは、ストリームの計算された平均速度、完了にどれだけ近いか (計算された/予測された進行状況の値に基づく)、および予想される完了時間に依存し、目的のデータ チャンクを取得する相対的なユーティリティに対して加重されます。

于 2011-08-29T05:39:18.623 に答える
0

いいえ; これを実行できる API はありません。

ハンドルを閉じるのは古いトリックです。これは、NT の時代にまでさかのぼって機能します。ただし、ハンドルに対するすべての未処理の操作がエラーで完了します。

キャンセルにも同様の問題CancelIoExがあります。お使いのプラットフォームでは利用できない場合があることに注意してください。

SetCommTimeoutsこれは、シリアル ポートおよびその他の通信デバイス ハンドルでのみ機能するため、オプションではありません。

取り消しは、歴史的に、デバイス ドライバーを作成する上で最も難しい部分の 1 つです。最近では、カーネルにはキャンセル セーフ キューのサポートが XP に組み込まれており (2K に移植可能)、はるかに簡単になっています。しかし、多くのドライバー (特に年配のドライバー) はとにかくキャンセルを無視します (これは合法です)。

より高いレベルの抽象化で「キャンセル」を実装することをお勧めします。ハンドルを閉じるか、操作を完了させて、結果を無視します。

于 2011-09-02T14:09:37.953 に答える