gpt4 book ai didi

c# - Task.WhenAll 为 Task 创建副本

转载 作者:太空宇宙 更新时间:2023-11-03 22:43:25 26 4
gpt4 key购买 nike

创建任务列表的类,每个任务返回 ConcurrentDictionary

public List<Task<ConcurrentDictionary<int, object>>> GetDictionaries()
{
var results = new ConcurrentDictionary<int, object>();
var tasks = new List<Task<ConcurrentDictionary<int, object>>>();

for (var k = 0; k < 10; k++)
{
tasks.Add(Task.Run(() =>
{
var done = false;
var data = new Object();
var eventCallback = (int id) => { data.id = id; done = true; };

Client.asyncEvent += eventCallback;
Client.initiateAsyncEvent(k);
while (done == false);
Client.asyncEvent -= eventCallback;

results[k] = data;
return results;
}));
}

return tasks;
}

调用事件(任务)10次,等待此事件的回调,将结果添加到字典“results”中。

我们执行 10 个事件(任务),因此应该在字典中获取 10 个项目,但是当我使用 When.All 合并来自所有任务的字典时,列表包含 100 个项目而不是 10 个。

var tasks = GetDictionaries();

var plainListOfResults = Task
.WhenAll(tasks)
.Result
.SelectMany(o => o.Keys)
.ToList();

// Expected: [0,1,2,3,4,5,6,7,8,9]
// Actual: [0,1,2,3,4,5,6,7,8,9, 0,1,2,3,4,5,6,7,8,9 ... 0,1,2,3,4,5,6,7,8,9]

问题

  1. 为什么 10 项任务创造的结果是应有的 10 倍?
  2. 为什么当我将 ConcurrentDictionary 替换为 Dictionary 时,此代码会按预期工作?

最佳答案

每个 Task 都返回整个 ConcurrentDictionary,因此当您从 Task.WhenAll 获取结果集时,它包含相同的字典 10次。

一些补充说明:

while (done == false); 太糟糕了。它可能在等待时将您的 CPU 锁定在 100%。如果您要将基于事件的异步转换为基于任务的异步,请将您的事件转换为任务,或使用 TaskCompletionSource

https://learn.microsoft.com/en-us/dotnet/standard/asynchronous-programming-patterns/interop-with-other-asynchronous-patterns-and-types

如果您可以重构以便异步方法只返回值,例如 ValueTupleTupleKeyValuePair、匿名类型或您自己的类型,并且在运行时不要修改字典,您也可以放弃 ConcurrentDictionary 并仅在 ToDictionary 之后从结果集中创建字典 Task.WhenAll.

关于c# - Task.WhenAll 为 Task<ConcurrentDictionary> 创建副本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51120453/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com