创建任务列表的类,每个任务返回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次,等待该事件的回调,然后将结果添加到字典“结果”中。
我们执行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]
问题
答案 0 :(得分:3)
每个Task
都将返回整个ConcurrentDictionary
,因此当您从Task.WhenAll
获得一组结果时,它包含10次相同的字典。
一些附加说明:
while (done == false);
很糟糕。等待期间,可能会将您的CPU固定在100%。如果要将基于事件的异步转换为基于任务的异步,请将事件转换为任务,或使用TaskCompletionSource
如果您可以重构,以便异步方法仅返回值,例如ValueTuple
,Tuple
,KeyValuePair
,匿名类型或您自己的类型,则不要修改字典运行时,您也可以抛弃ConcurrentDictionary
并仅在ToDictionary
之后使用Task.WhenAll
从结果集中创建字典。