我有一个控制台应用程序,它调用 Web API 并获取服务列表。 然后,它会循环访问并调用每个服务。
我有以下几点:
static int Main(string[] args)
{
...
Task.WaitAll(Process());
}
private static async Task BeginProcess()
{
using(HttpClientHandler handler = new HttpClientHandler())
{
handler.UseDefaultCredentials = true;
using(var client = new HttpClient(handler))
{
var response = client.GetStringAsync(_baseUrl);
List<Service> services = new List<Service>();
services = jss.Deserialize<List<Service>>(response.Result);
client.Timeout = new TimeSpan(0,3,0);
foreach(var service in services)
{
Console.WriteLine("Running " + service.Name);
var _serviceResponse = await client.PostAsync(_baseURL + service.Id.ToString(), null);
Console.WriteLine(service.Name + " responded with " + _serviceRepsonse.StatusCode);
}
}
}
}
遗憾的是,此代码按顺序处理每个服务,而不是并行进行调用。 问题是,我不确定如何使这些调用并行运行。
答案可以在 C# 说明书中的并发中找到:
static async Task<string> DownloadAllAsync(IEnumerable<string> urls){
var httpClient = new HttpClient();
var downloads = urls.select(url => httpClient.getStringAsync(url));
Task<string>[] tasks = downloads.ToArray(); //-> tasks are started
//now that you have an array of tasks you can wait for them all to finish
string[] htmlPages = await Task.WhenAll(tasks);
return string.Concat(htmlPages);
}
这里的关键点是:
- 安排代码获取任务数组(不同的容器也可以,不一定是数组)
- 使用 await Task.WhenAll(任务数组);
虽然我已经接受了答案,但我终于找到了这个我觉得更简洁的答案。
await Task.WhenAll(services.Select(async s => {
Console.WriteLine("Running " + s.Name);
var _serviceResponse = await client.PostAsync(...);
Console.WriteLine(s.Name + " responded with " + _serviceResponse.StatusCode);
}));
正如
@SLaks提到的,你需要用这些行替换你的循环......
var asyncTasks = new Dictionary<Service, Task>();
foreach(var service in services)
{
Console.WriteLine("Running " + service.Name);
asyncTasks.Add(service, client.PostAsync(_baseURL + service.Id.ToString(), null));
}
// All tasks are running, so wait for all of them to finish here
await Task.WhenAll(asyncTasks);
foreach(var service in asyncTasks.Keys) {
Console.WriteLine("Service " + service.Name + " returned " + syncTasks[service].Result);
}
希望对您有所帮助。
更改以下内容:
foreach(var service in services)
{
Console.WriteLine("Running " + service.Name);
var _serviceResponse = await client.PostAsync(_baseURL + service.Id.ToString(), null);
Console.WriteLine(service.Name + " responded with " + _serviceRepsonse.StatusCode);
}
对此:
var serviceCallTaskList = new List<Task<HttpResponseMessage>>();
foreach(var service in services)
{
Console.WriteLine("Running " + service.Name);
serviceCallTaskList.Add(client.PostAsync(_baseURL + service.Id.ToString(), null));
}
HttpResponseMessage[] responseArray = await Task.WhenAll(serviceCallTaskList);
for(int i = 0; i < responseArray.Length; i++)
{
Console.WriteLine(services[i].Name + " responded with " + responseArray[i].StatusCode);
}