1

リストに保持している多くのURLを呼び出すために、BeginGetResponseメソッドを使用したいと思います。これを実装する方法について2つの質問があります。

  1. http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.begingetresponse(v=vs.95).aspxの例によると

を使用しております:

public static ManualResetEvent allDone= new ManualResetEvent(false);

他のスレッドと共有されているので、Webアプリケーションで静的メンバーを使用するのは賢明ですか?これは問題を引き起こす可能性がありますか?

  1. すべてのコールバックがいつ終了したかをどのように知ることができますか?結果の要約レポートを作成する必要があります

ありがとう

4

3 に答える 3

3

イベントを使用できますが、次のようにクラスTask<T>FromAsyncメソッドを使用することをお勧めします。TaskFactory

// Execution of tasks starts here because of the
// call to ToArray.
Task<WebResponse>[] tasks = uris.Select(u => {
    // Create the request.
    WebRequest req = ...;

    // Make the call to return the response asynchronously with
    // a Task.
    return Task.Factory.FromAsync(req.BeginGetResponse,
        req.EndGetResponse, null);
}).ToArray();

それができたら、クラスのメソッドTask<T>を使用してすべてのインスタンスを簡単に待つことができます。ContinueWhenAllTaskFactory

Task.Factory.ContinueWhenAll(tasks, t => {
     // Note that t is an array of Task, so you have to cast 
     // each element to a Task<WebRequest>.
     // Process all of them here.
});

上記は、Task完了するまで待機するか、続行する必要がある a を返すことに注意してください (通知が心配な場合)。

.NET 4.5 を使用している場合、クラスでContinueWhenAllメソッドを使用する必要はありませんが、クラスでメソッドを使用して作業を実行できます。TaskFactoryWhenAllTask

// Note that work does not start here yet because of deferred execution.
// If you want it to start here, you can call ToArray like above.
IEnumerable<Task<WebResponse>> tasks = uris.Select(u => {
    // Create the request.
    WebRequest req = ...;

    // Make the call to return the response asynchronously with
    // a Task.
    return Task.Factory.FromAsync(req.BeginGetResponse,
        req.EndGetResponse, null);
});

// Execution will start at this call:
Task<Task<WebRequest>[]> allTasks = Task.WhenAll(tasks);

// Continue or wait here.

上記は、.NET 3.5 が使用されていることが明らかになる前のものであることに注意してください。

于 2012-07-10T19:45:15.357 に答える
1
  1. 完了するまでメイン スレッドで待機する場合、このソリューションはあまり適していません。最初のリクエストは、イベントの状態を「設定」に変更します。したがって、メイン スレッドは、最初の要求が完了した後も実行を継続します。
  2. CountdownEventを使用することをお勧めします。

       using(var countdownEvent = new CountdownEvent(list.Count))
       {
           // launch requests with countdownEvent.Signal(); in the end
           countdownEvent.Wait();
       }
    

    RequestState 内に countdownEvent への参照を格納する必要があります。また、タイムアウトを制御することを忘れないでください - で新しいスレッドを開始してThreadPool.RegisterWaitForSingleObjectください。

于 2012-07-10T19:56:19.687 に答える
1

私はあなたがこのようなことをしようとしていると思います:

int total = urls.Count;
ManualResetEvent evt = new ManualResetEvent();
ConcurrentBag<WebResponses> responses = new ConcurrentBag<WebResponse>();

foreach(Uri in uri)
{
    HttpWebRequest req = ...;
    req.BeginGetResponse(res=>
    {
        WebResponse res = req.EndGetResponse();

        // do what you need with the response.
        // maybe add it to a collection so you can report on it later:
        responses.Add(res);

        if(Interlocked.Decrement(ref total) == 0)
        {
            // this was the last response. set event.
            evt.Set();
        }
    }, null);
}

evt.Wait();

foreach(WebResponse res in responses)
{
    // report something about the response.
}

最適なワークフローはイベントを必要としないことに注意してください。余分なクレジットを得るために、それをすべてまとめて取り除き、イベントを設定する if 内に最終的なロジックを移動します。

また、このコードはテストされておらず、エラー処理が欠けています。

于 2012-07-10T19:30:31.197 に答える