6

私は一般的に、インターフェースを部分的に実装することに慎重です。ただし、IAsyncResultいくつかのまったく異なる使用パターンをサポートしていることを考えると、これは少し特殊なケースです。を呼び出したり、 を使用したり、ポーリングしたりするのではなく、 AsyncState/パターンをどのくらいの頻度で使用/使用していますか?AsyncCallbackEndInvokeAsyncWaitHandleIsCompleted

関連する質問: ThreadPool WorkItem が完了したことを検出する/完了を待機しています。

このクラスを検討してください(非常に近似、ロックが必要です):

public class Concurrent<T> {
    private ManualResetEvent _resetEvent;
    private T _result;

    public Concurrent(Func<T> f) {
        ThreadPool.QueueUserWorkItem(_ => {
                                         _result = f();
                                         IsCompleted = true;
                                         if (_resetEvent != null)
                                             _resetEvent.Set();
                                     });
    }

    public WaitHandle WaitHandle {
        get {
            if (_resetEvent == null)
                _resetEvent = new ManualResetEvent(IsCompleted);
            return _resetEvent;
        }

    public bool IsCompleted {get; private set;}
    ...

(ドキュメントで説明されているように、遅延して作成された)とがWaitHandleありますが、 (?)の賢明な実装は見当たりません。それで、それを実装するのは理にかなっていますか? Parallel Extensions ライブラリでは が実装されていますが、暗黙的に実装されているだけであることに注意してください。IAsyncResultIsCompletedAsyncState{return null;}IAsyncResultTaskIAsyncResultIsCompleted

4

2 に答える 2

3

いくつか質問があるようです。個別に処理しましょう

WaitHandle の遅延作成

はい、これが最も正しいアプローチです。これはスレッド セーフな方法で行う必要がありますが、怠惰な方法が適しています。

ただし、秘訣は WaitHandle を破棄することです。WaitHandle は IDisposable のベースであり、タイムリーに破棄する必要があります。IAsycResult のドキュメントでは、このケースはカバーされていません。これを行う最善の方法は、EndInvoke です。BeginInvoke のドキュメントには、BeginInvoke ごとに、対応する EndInvoke (または BeginRead/EndRead) が必要であることが明示的に記載されています。これは、WaitHandle を破棄するのに最適な場所です。

AsyncState はどのように実装する必要がありますか?

IAsyncResult を返す標準 BCL API を見ると、それらのほとんどは状態パラメーターを取ります。これは通常、AsyncState から返される値です (例については、ソケット API を参照してください)。IAsyncResult を返す任意の API BeginInvoke スタイル API のオブジェクトとして型指定された状態変数を含めることをお勧めします。必須ではありませんが、良い習慣です。

状態変数がない場合、null を返すことは許容されます。

IsCompleted API

これは、IAsyncResult を作成する実装に大きく依存します。しかし、はい、実装する必要があります。

于 2009-01-02T02:02:36.680 に答える
2
  • 私の経験では、待機したり、最初にコールバックされたりせずにEndInvokeを呼び出すだけでは、ほとんど役に立ちません。
  • クライアントが一度に複数の操作を待ちたい場合があるため、コールバックを提供するだけでは不十分な場合があります(WaitAny、WaitAll)
  • 私はIsCompletedをポーリングしたことがありません、確かにそうです!したがって、IsCompletedの実装を保存することはできますが、それは非常に単純なので、クライアントを驚かせる可能性はないようです。

したがって、非同期で呼び出し可能なメソッドの合理的な実装は、完全に実装されたIAsyncResultを実際に提供する必要があります。

ところで、多くの場合、自分でIAsyncResultを実装する必要はなく、Delegate.BeginInvokeによって返されるものを返すだけです。例については、System.IO.Stream.BeginReadの実装を参照してください。

于 2009-01-02T00:04:50.910 に答える