我试图围绕async
/ await
,并想知道这是否正确使用Task.WhenAll
方法:
public class AsyncLib
{
public async Task<IEnumerable<string>> DoIt()
{
var urls = new string[] { "http://www.msn.com", "http://www.google.com" };
var tasks = urls.Select(x => this.GetUrlContents(x));
var results = await Task.WhenAll(tasks);
return results.Select(x => x);
}
public async Task<string> GetUrlContents(string url)
{
using (var client = new WebClient())
{
return await client.DownloadStringTaskAsync(url);
}
}
}
主要
这是调用控制台应用程序。
class Program
{
static void Main(string[] args)
{
var lib = new AsyncLib();
foreach(var item in lib.DoIt().Result)
{
Console.WriteLine(item.Length);
}
Console.Read();
}
}
答案 0 :(得分:15)
您当前代码的问题在于,如果有多个任务抛出,您将无法处理个别异常。
如果这是一个问题,那么使用以下方法,您可以处理它们:
public async Task<Task<string>[]> DoIt()
{
var urls = new string[] { "http://www.msn.com", "http://www.google.com" };
var tasks = urls.Select(x => this.GetUrlContents(x)).ToArray();
await Task.WhenAll(tasks);
return tasks;
}
// ...
static void Main(string[] args)
{
var lib = new AsyncLib();
foreach(var item in lib.DoIt().Result)
{
Console.WriteLine(item.Result.Length);
}
Console.Read();
}
注意我使用ToArray()
来避免评估可枚举和多次启动任务(因为LINQ是惰性求值的)。
已更新,现在您可以通过取消DoIt
来进一步优化async/await
:
public Task<Task<string>[]> DoIt()
{
var urls = new string[] { "http://www.msn.com", "http://www.google.com" };
var tasks = urls.Select(x => this.GetUrlContents(x)).ToArray();
return Task.Factory.ContinueWhenAll(
tasks,
_ => tasks,
CancellationToken.None,
TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
}
但是,如果您这样做,请注意exception propagation behavior。
中的更改