Web应用程序中的BeginGetResponse

时间:2012-07-10 19:11:36

标签: c# multithreading .net-3.5

我想使用BeginGetResponse方法来调用我在列表中保存的许多URL。 我有两个关于如何实现这个问题的问题:

  1. 根据http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.begingetresponse(v=vs.95).aspx
  2. 中的示例

    我们使用:

    public static ManualResetEvent allDone= new ManualResetEvent(false);
    

    在Web应用程序中使用静态成员是明智的,因为它与其他线程共享?这会导致问题吗?

    1. 如何判断所有回调何时结束?我需要对结果进行总结报告
    2. 由于

3 个答案:

答案 0 :(得分:3)

虽然您可以使用某个活动,但我建议您使用Task<T>FromAsync method上的TaskFactory class,如下所示:

// 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>类上的ContinueWhenAll method轻松等待所有TaskFactory个实例,如下所示:

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,您必须等待或继续完成(如果您担心通知)。

如果您使用的是.NET 4.5,则无需在ContinueWhenAll课程中使用TaskFactory方法,但可以使用Task上的WhenAll method上课要做的工作:

// 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.

请注意,上述内容早于it was revealed that .NET 3.5 was being used

答案 1 :(得分: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.
}

请注意,最佳工作流程不需要事件。为了获得额外的功劳,可以将它们全部放在一起,并将最终的逻辑移动到设置事件的内部。

此外,此代码未经测试且缺少错误处理,因此请确保在完全使用它时添加该代码。

答案 2 :(得分:1)

  1. 如果你想在主线程中等待completition,那么这个解决方案不是很好。第一个请求会将事件的状态更改为“设置”。因此,主线程将在第一个请求完成后继续执行。
  2. 建议你使用CountdownEvent

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

    您必须在RequestState中存储对countdownEvent的引用。此外,不要忘记控制超时 - 使用ThreadPool.RegisterWaitForSingleObject启动新主题。