使用 Task.WhenAll,或不使用 Task.WhenAll

Mat*_*att 2 c# async-await

我正在审查一些代码并试图提出一个技术原因,为什么您应该或不应该使用Task.WhenAll(Tasks[])并行进行 Http 调用。Http 调用调用不同的微服务,我猜其中一个调用可能需要也可能不需要一些时间来执行......(我想我对此并不感兴趣)。我正在使用 BenchmarkDotNet 来让我了解是否消耗了更多内存,或者执行时间是否有很大不同。以下是基准的过度简化示例:

[Benchmark]
public async Task<string> Task_WhenAll_Benchmark()
{
  var t1 = Task1();
  var t2 = Task2();

  await Task.WhenAll(t1, t2);

  return $"{t1.Result}===={t2.Result}";
}

[Benchmark]
public async Task<string> Task_KeepItSimple_Benchmark()
{
  return $"{await Task1()}===={await Task2()}";
}
Run Code Online (Sandbox Code Playgroud)

Task1Task2方法真的很简单(我HttpClient在类中有一个静态)

public async Task<string> Task1()
{
  using (var request = await httpClient.GetAsync("http://localhost:8000/1.txt"))
  {
    return $"task{await request.Content.ReadAsStringAsync()}";
  }
}

public async Task<string> Task2()
{
  using (var request = await httpClient.GetAsync("http://localhost:8000/2.txt"))
  {
    return $"task{await request.Content.ReadAsStringAsync()}";
  }
}
Run Code Online (Sandbox Code Playgroud)

还有我的结果

方法 意思 错误 标准差 第 0 代 第一代 第 2 代 已分配
Task_WhenAll_Benchmark 1.138 毫秒 0.0561 毫秒 0.1601 毫秒 —— —— —— 64 KB
Task_KeepItSimple_Benchmark 1.461 毫秒 0.0822 毫秒 0.2331 毫秒 —— —— —— 64 KB

如您所见,内存不是问题,执行时间也不长。

我的问题真的是,是否有技术原因为什么你应该或不使用 Task.WhenAll()?这只是一种偏好吗?

我从 .net 核心团队的一个人那里看到了Async Guidance,但它并没有真正涵盖这种情况。

编辑:这是 .net 框架(4.6.1)而不是核心!

编辑 2:按照下面评论中的建议更新基准之一。

我更新了 KeepItSimple 方法的基准测试...

[Benchmark]
public async Task<string> Task_KeepItSimple_Benchmark()
{
  var t1 = Task1();
  var t2 = Task2();

  return $"{await t1}===={await t2}";
}
Run Code Online (Sandbox Code Playgroud)

并有以下结果:

方法 意思 错误 标准差 第 0 代 第一代 第 2 代 已分配
Task_WhenAll_Benchmark 1.134 毫秒 0.0566 毫秒 0.1613 毫秒 —— —— —— 64 KB
Task_KeepItSimple_Benchmark 1.081 毫秒 0.0377 毫秒 0.1070 毫秒 —— —— —— 64 KB

现在我更加困惑 - 执行速度如何(尽管数量很少!)?我认为当你await得到结果时开始执行代码......

Ste*_*ary 8

我的问题真的是,是否有技术原因为什么你应该或不使用 Task.WhenAll()?

在两个调用都失败的异常情况下,行为略有不同。如果await一次修改一次,则永远不会观察到第二次失败;第一次失败的异常会立即传播。如果使用Task.WhenAll,则观察到两种故障;两个任务都失败后会传播一个异常。

这只是一种偏好吗?

这主要只是偏好。我倾向于更喜欢,WhenAll因为代码更明确,但我一次await输入一个没有问题。

  • @ADyson:好点;那么它们将是连续的。如果示例代码是 `return $"{await task1}===={await task2}";`,我的答案是正确的 (2认同)