如何将 Dictionary<string, Task<int>> 转换为 Task<Dictionary<string, int>>

And*_*eas 3 c# asynchronous task-parallel-library async-await

我正在努力使用 http 请求检索大约 10 种不同类型的数据,它们之间的依赖关系相当复杂。我正在尝试以一种优雅、可读和可维护的方式找到解决这个问题的方法,而无需不必要的等待。

让我们假设,某种方法创建了一个Dictionary<string, Task<int>>. 将其转换为最优雅的方式是什么Task<Dictionary<string, int>>

Task一旦字典中包含的所有任务完成,新的外部就应该完成。

当然,我可以手动编写:

Dictionary<string, Task<int>> values = GetValues();
Task<Dictionary<string, int>> result = Task.Run(async () => {
    Dictionary<string, int> rewrapped = new();
    foreach (var entry in values) {
        rewrapped.Add(entry.Key, await entry.Value);
    }
    return rewrapped;
});
Run Code Online (Sandbox Code Playgroud)

但难道就没有更好的办法吗?

wer*_*zui 5

经验法则:永远不要使用Task.Run它,而不是真正的异步,它将使用线程来模拟异步!

您只需等待值,然后获取结果:

Dictionary<string, Task<int>> values = GetValues();
await Task.WhenAll(values.Values);
Dictionary<string, int> results = values.ToDictionary(p => p.Key, p => p.Value.Result);
Run Code Online (Sandbox Code Playgroud)

如果您确实想要一个Task<Dictionary<string, int>>.

async Task<Dictionary<string, int>> Unwrap(Dictionary<string, Task<int>> values)
{
    await Task.WhenAll(values.Values);
    return values.ToDictionary(p => p.Key, p => p.Value.Result);
}
Run Code Online (Sandbox Code Playgroud)

  • @TheodorZoulias `.ConfigureAwait(false)` 这里没有丢失。我们不知道 OP 是否需要 `.ConfigureAwait(true)` (这是默认值),或者他是否在 .Net Core 或 .Net &gt; 5 中运行,其中没有延续上下文,因此 `.ConfigureAwait(false)`不会有任何影响。 (2认同)