我想使用BeginGetResponse方法来调用我在列表中保存的许多URL。 我有两个关于如何实现这个问题的问题:
我们使用:
public static ManualResetEvent allDone= new ManualResetEvent(false);
在Web应用程序中使用静态成员是明智的,因为它与其他线程共享?这会导致问题吗?
由于
答案 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)
建议你使用CountdownEvent:
using(var countdownEvent = new CountdownEvent(list.Count))
{
// launch requests with countdownEvent.Signal(); in the end
countdownEvent.Wait();
}
您必须在RequestState中存储对countdownEvent的引用。此外,不要忘记控制超时 - 使用ThreadPool.RegisterWaitForSingleObject
启动新主题。