我正在探索async
/ await
,并且发现了一个奇怪的场景,需要解决方案方面的指导。
作为参考,可以在这里找到此问题中看到的代码:
https://github.com/Mike-EEE/Stash/tree/master/AwaitPerformance
我提供了两种等待一组任务的简单方法。首先是简单地创建一个List<Task>
,将任务添加到此列表中,并通过调用Task.WhenAll
立即等待整个结果:
public async Task<uint> AwaitList()
{
var list = new List<Task>();
for (var i = 0u; i < 10; i++)
{
list.Add(Task.Delay(1));
}
await Task.WhenAll(list).ConfigureAwait(false);
return 123;
}
第二个方法是等待每个任务在for
循环中发生:
public async Task<uint> AwaitEach()
{
for (var i = 0u; i < 10; i++)
{
await Task.Delay(1).ConfigureAwait(false);
}
return 123;
}
但是,当使用Benchmark.NET运行这两种方法时,我得到的结果却令人惊讶地矛盾:
// * Summary *
BenchmarkDotNet=v0.11.5, OS=Windows 10.0.18362
AMD Ryzen 7 2700X, 1 CPU, 8 logical and 4 physical cores
.NET Core SDK=3.0.100-preview5-011568
[Host] : .NET Core 3.0.0-preview5-27626-15 (CoreCLR 4.6.27622.75, CoreFX 4.700.19.22408), 64bit RyuJIT
DefaultJob : .NET Core 3.0.0-preview5-27626-15 (CoreCLR 4.6.27622.75, CoreFX 4.700.19.22408), 64bit RyuJIT
| Method | Mean | Error | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated |
|---------- |----------:|----------:|----------:|------:|------:|------:|----------:|
| AwaitList | 15.60 ms | 0.0274 ms | 0.0243 ms | - | - | - | 2416 B |
| AwaitEach | 155.62 ms | 0.9113 ms | 0.8524 ms | - | - | - | 352 B |
如您所见,等待任务列表要快得多,但是会产生大量分配。但是,等待每一项都是相反的:它速度较慢,但产生的垃圾少。
我是否有一种显而易见的理想方法来让这两个世界都处于最佳境地?也就是说,是否有一种方法可以等待一组Task
元素,这些元素既快速又导致分配量低?
在此先感谢您的帮助。
答案 0 :(得分:4)
您不是要在这里比较苹果。
在您的示例中:
AwaitList创建一个任务列表,然后并行(异步)运行它们。
AwaitEach依次运行每个Task,因此使async关键字无用。
但是,如果您列出了任务列表,以便可以启动每个任务,然后比较WhenAll与循环,则您的比较将如下所示:
public async Task<uint> AwaitList()
{
var list = new List<Task>();
for (var i = 0u; i < 10; i++)
{
list.Add(Task.Delay(1));
}
await Task.WhenAll(list).ConfigureAwait(false);
return 123;
}
经文
public async Task<uint> AwaitEach()
{
var list = new List<Task>();
for (var i = 0; i < 10; i++)
{
list.Add(Task.Delay(1));
}
for (var i = 0; i < 10; i++)
{
await list[i].ConfigureAwait(false);
}
return 123;
}
现在比较这两个功能的统计信息,您会发现它们是彼此的基石。