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

prd*_*prd 4 c# asynchronous

一般信息

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

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();
}
Run Code Online (Sandbox Code Playgroud)

此外,我已经实现了以下方法,以测试哪种方法执行时间最短。

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

检测结果

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

发出50个HTTP请求

  1. TaskWhenAll:〜650ms
  2. 多次等待:〜4500ms

为什么选择这种方法Task.WhenAll要比使用另一种方法快得多,并且会带来负面影响(例如,异常处理等)?

Joh*_*nny 5

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

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

使用多次等待方法,可以通过await GetPostAsync(postId)from foreach循环一个接一个地依次发出HTTP请求。您启动了任务,但是同时,您创建了一个挂起点并等待其完成。

选择这种方法与其他方法相比是否有负面影响(例如,异常处理等)?

没有负面影响,使用await/async模式处理异常变得像平常一样使用using try-catch块。WhenAll将汇总处于Faulted状态的每个任务的所有异常。