与Task.WhenAll相比,多次等待的性能

时间:2019-04-12 16:26:35

标签: c# asynchronous

一般信息

我想提高程序的性能,向同一外部API端点发出多个HTTP请求。因此,我创建了一个控制台应用程序来执行一些测试。方法GetPostAsync向外部API发送异步HTTP请求,并以字符串形式返回结果。

private static async Task<string> GetPostAsync(int id)
{
    var client = new HttpClient();
    var response = await client.GetAsync($"https://jsonplaceholder.typicode.com/posts/{id}");
    return await response.Content.ReadAsStringAsync();
}

此外,我还实现了以下方法,以测试执行时间最短的方法。

private static async Task TaskWhenAll(IEnumerable<int> postIds)
{   
    var tasks = postIds.Select(GetPostAsync);
    await Task.WhenAll(tasks);
}

private static async Task MultipleAwait(IEnumerable<int> postIds)
{
    foreach (var postId in postIds)
    {
        await GetPostAsync(postId);
    }
}

测试结果

使用集成的Stopwatch类,我测量了这两种方法的执行时间,有趣的是,使用Task.WhenAll的方法比其他方法的效果更好:

  

发出50个HTTP请求

     
      
  1. TaskWhenAll:〜650ms
  2.   
  3. MultipleAwait:〜4500ms
  4.   

为什么使用Task.WhenAll的方法如此之快,并且在选择这种方法时会产生负面影响(例如,异常处理等)?

1 个答案:

答案 0 :(得分:5)

  

为什么使用Task.WhenAll的方法这么快

速度更快,因为您不等待GetPostAsync。因此,实际上,每次您await client.GetAsync($"https://jsonplaceholder.typicode.com/posts/{id}");控件都会返回给调用方,然后调用方可以发出另一个HTTP请求。如果您认为HTTP请求比创建新客户端长得多,则可以通过并行运行多个HTTP请求来有效地具有并行性。 WhenAll只会创建一个悬浮点,并等待所有任务完成。

使用多次等待方法,您可以从await GetPostAsync(postId)循环通过foreach依次发出HTTP请求。您开始执行任务,但与此同时,您创建了一个挂起点并等待其完成。

  

在以下情况下是否有任何负面影响(即异常处理等)   选择这种方法而不是其他方法?

使用await/async模式处理异常不会产生负面影响,就像通常使用try-catch块一样。 WhenAll将汇总处于Faulted状态的每个任务的所有异常。