【发布时间】:2021-05-14 19:58:22
【问题描述】:
我正在审查一些代码并试图提出一个技术原因,说明您应该或不应该使用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()}";
}
Task1 和 Task2 方法非常简单(我在类中有一个静态的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()}";
}
}
我的结果
| Method | Mean | Error | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated |
|---|---|---|---|---|---|---|---|
| Task_WhenAll_Benchmark | 1.138 ms | 0.0561 ms | 0.1601 ms | - | - | - | 64 KB |
| Task_KeepItSimple_Benchmark | 1.461 ms | 0.0822 ms | 0.2331 ms | - | - | - | 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}";
}
并得到以下结果:
| Method | Mean | Error | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated |
|---|---|---|---|---|---|---|---|
| Task_WhenAll_Benchmark | 1.134 ms | 0.0566 ms | 0.1613 ms | - | - | - | 64 KB |
| Task_KeepItSimple_Benchmark | 1.081 ms | 0.0377 ms | 0.1070 ms | - | - | - | 64 KB |
现在我更加困惑 - 执行速度如何更快(尽管数量很少!)?我以为代码的执行是在你await 结果时开始的......
【问题讨论】:
-
使用
Task.WhenAll(Tasks[])或await t1应该没有太大区别;然后await t2;仅用于两个任务。如果你await t1和t2在t1之前完成,那么await t2只会遇到一个已完成的任务。当您增加任务数量时,差异会更加明显。 -
不应该将
Task_KeepItSimple_Benchmark与Task_WhenAll_Benchmark中的var t1 = Task1();var t2 = Task2();匹配以进行公平比较吗?在Task_KeepItSimple_Benchmark中,您正在等待 task1 的所有内容,然后 task2 才能启动。 -
同意,保持简单,目前按顺序执行它们,所以这不是一个真正有效的比较
-
I thought execution of the code started when you await the result- 一点也不。 method begins executing when it is called。await(或“异步等待”)是调用代码(异步)等待方法完成的时间。 -
how is the execution faster...时间量和它们之间的差距是如此微小,以至于网络条件或服务器负载的轻微变化很容易导致这种情况,即使您使用的是本地服务器。您必须对其进行数十次测试才能开始获得任何有意义的平均值。
标签: c# async-await