Task.WhenAll 为任务创建副本<ConcurrentDictionary>
Task.WhenAll creates duplicates for Task<ConcurrentDictionary>
Class 创建任务列表,每个任务 returns 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]
问题
- 为什么 10 个任务创造的结果比应有的多 10 倍?
- 为什么当我将 ConcurrentDictionary 替换为 Dictionary 时,此代码按预期工作?
每个 Task
都是 return 整个 ConcurrentDictionary
所以当你从 Task.WhenAll
得到一组结果时,它包含相同的字典 10 次。
一些补充说明:
while (done == false);
太糟糕了。它可能在等待时将您的 CPU 固定在 100%。如果您要将基于事件的异步转换为基于任务的异步,请将您的事件转换为任务,或使用 TaskCompletionSource
如果您可以重构,以便异步方法只是 return 值,例如 ValueTuple
s、Tuple
s、KeyValuePair
s、匿名类型或您自己的类型,并且在 运行 时不要修改字典,您也可以放弃 ConcurrentDictionary
并仅根据 Task.WhenAll
之后的 ToDictionary
结果集创建字典。
Class 创建任务列表,每个任务 returns 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]
问题
- 为什么 10 个任务创造的结果比应有的多 10 倍?
- 为什么当我将 ConcurrentDictionary 替换为 Dictionary 时,此代码按预期工作?
每个 Task
都是 return 整个 ConcurrentDictionary
所以当你从 Task.WhenAll
得到一组结果时,它包含相同的字典 10 次。
一些补充说明:
while (done == false);
太糟糕了。它可能在等待时将您的 CPU 固定在 100%。如果您要将基于事件的异步转换为基于任务的异步,请将您的事件转换为任务,或使用 TaskCompletionSource
如果您可以重构,以便异步方法只是 return 值,例如 ValueTuple
s、Tuple
s、KeyValuePair
s、匿名类型或您自己的类型,并且在 运行 时不要修改字典,您也可以放弃 ConcurrentDictionary
并仅根据 Task.WhenAll
之后的 ToDictionary
结果集创建字典。