我有一个 url 列表。我 运行 OpenreadAsyn(url1) 到 OpenReadAsync(urlN) .. 我如何等待它们全部完成
I have a list of urls . I run OpenreadAsyn(url1) to OpenReadAsync(urlN) .. How do I wait for all of them to complete
我有一个长度为 N 的结果列表。
我有一个包含 N URL 的 URL 列表。
我需要执行以下操作。
List<Result> results=new List<Result>;
//Urls is a list of URLs.
public void FillResults()
{
foreach( var urlx in Urls)
{
GetResponse(urlx, (response) =>
{
if (response != null && response.StatusCode==200)
{
Result result=new Result;
result.Value=response.SomeValue;
result.url=urlx;------>It is important that SomeValue corresponds to urlx and not other say,urly
results.Add(result);
}
});
}
}
//wait till List results is completely filled
private void GetResponse(Uri uri, Action<MyResponse> callback)
{
using(var m_webClient = new WebClient())
{
m_webClient.OpenReadCompleted += (o, a) =>
{
if (callback != null)
{
DataContractJsonSerializer ser = new DataContractJsonSerializer(MyResponse));
callback(ser.ReadObject(a.Result) MyResponse);
}
};
m_webClient.OpenReadAsync(uri);
}
}
public class MyResponse:Response
{
}
// 等待结果列表填满
我希望每个请求都异步发生,但我想等到结果列表完全填满才能继续。
有两种解决方法。快速而肮脏的方法是添加一个计数器来告诉剩余多少作业会像调用 GetResponse
之前一样增加并在回调中减少,如果它达到 0,则调用流程中的下一步。由于竞争条件和不可预测的线程行为,这将是有风险的,例如,如果您调用一个请求,并且在第二个请求开始之前,它会尝试继续。
更好的解决方案是跟踪使用 OpenReadTaskAsync
而不是 OpenReadAsync
生成的任务,然后使用 Task.WhenAll({ALL YOUR TASKS})
.
它会稍微改变你的程序:
List<Result> result = new List<Result>();
List<Task<Stream>> jobs = new List<Task<Stream>>();
...
GetResponse
必须 return 一个简单明了的任务值。
private Task<Stream> GetResponse(Uri uri, Action<MyResponse> callback)
{
... //Almost all of your code stays the same,
//though you should close the stream you receive in the OnReadCompleted callback.
return m_webClient.OpenReadTaskAsync(uri.ToString());
}
在FillResults
方法的最后,您必须将这些任务添加到列表中并等待。
public async Task FillResults()
{
foreach( var urlx in Urls)
{
jobs.Add(
GetResponse(urlx, (response) =>
{
if (response != null && response.StatusCode==200)
{
Result result=new Result;
result.Value=response.SomeValue;
result.url=urlx;------>It is important that SomeValue corresponds to urlx and not other say,urly
results.Add(result);
}
})
);
}
await Task.WhenAll(jobs);
//Or Task.WhenAll(jobs).ContinueWith({AN ACTION CALLBACK})
//if you want to keep the return as a void;
}
现在您可以在调用该方法的任何地方等待 FillResults 函数,或者使用另一个回调来处理
的完成
我有一个长度为 N 的结果列表。 我有一个包含 N URL 的 URL 列表。 我需要执行以下操作。
List<Result> results=new List<Result>;
//Urls is a list of URLs.
public void FillResults()
{
foreach( var urlx in Urls)
{
GetResponse(urlx, (response) =>
{
if (response != null && response.StatusCode==200)
{
Result result=new Result;
result.Value=response.SomeValue;
result.url=urlx;------>It is important that SomeValue corresponds to urlx and not other say,urly
results.Add(result);
}
});
}
}
//wait till List results is completely filled
private void GetResponse(Uri uri, Action<MyResponse> callback)
{
using(var m_webClient = new WebClient())
{
m_webClient.OpenReadCompleted += (o, a) =>
{
if (callback != null)
{
DataContractJsonSerializer ser = new DataContractJsonSerializer(MyResponse));
callback(ser.ReadObject(a.Result) MyResponse);
}
};
m_webClient.OpenReadAsync(uri);
}
}
public class MyResponse:Response
{
}
// 等待结果列表填满
我希望每个请求都异步发生,但我想等到结果列表完全填满才能继续。
有两种解决方法。快速而肮脏的方法是添加一个计数器来告诉剩余多少作业会像调用 GetResponse
之前一样增加并在回调中减少,如果它达到 0,则调用流程中的下一步。由于竞争条件和不可预测的线程行为,这将是有风险的,例如,如果您调用一个请求,并且在第二个请求开始之前,它会尝试继续。
更好的解决方案是跟踪使用 OpenReadTaskAsync
而不是 OpenReadAsync
生成的任务,然后使用 Task.WhenAll({ALL YOUR TASKS})
.
它会稍微改变你的程序:
List<Result> result = new List<Result>();
List<Task<Stream>> jobs = new List<Task<Stream>>();
...
GetResponse
必须 return 一个简单明了的任务值。
private Task<Stream> GetResponse(Uri uri, Action<MyResponse> callback)
{
... //Almost all of your code stays the same,
//though you should close the stream you receive in the OnReadCompleted callback.
return m_webClient.OpenReadTaskAsync(uri.ToString());
}
在FillResults
方法的最后,您必须将这些任务添加到列表中并等待。
public async Task FillResults()
{
foreach( var urlx in Urls)
{
jobs.Add(
GetResponse(urlx, (response) =>
{
if (response != null && response.StatusCode==200)
{
Result result=new Result;
result.Value=response.SomeValue;
result.url=urlx;------>It is important that SomeValue corresponds to urlx and not other say,urly
results.Add(result);
}
})
);
}
await Task.WhenAll(jobs);
//Or Task.WhenAll(jobs).ContinueWith({AN ACTION CALLBACK})
//if you want to keep the return as a void;
}
现在您可以在调用该方法的任何地方等待 FillResults 函数,或者使用另一个回调来处理
的完成