2014-05-13 45 views
9

我试图总结我的周围async/await头,想知道这是否是正确使用方法Task.WhenAll的:正确使用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(); 

    } 
} 
+2

定义“正确”..? –

+0

@SimonWhitehead - 我是新来的异步/等待,所以只是试图包裹我的头。适当的我猜会意味着“有更好的方法吗?” – Sam

+1

这通常是我/做过的。你需要等待一组异步完成的任务。'WhenAll'通常是你如何做的(我知道的)。 –

回答

14

您当前的代码的问题是,如果多个任务抛出,您将无法处理个别异常。

如果这是一个问题,然后用下面的方法,您可以处理它们:

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是懒惰-evaluated)。

更新,现在你还可以通过消除async/await优化DoIt

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变化。

+3

+1指出Select的懒惰评价。 –