使用. continuewith()的竞争条件
本文关键字:竞争 条件 continuewith 使用 | 更新日期: 2023-09-27 18:16:18
我在一个很难重现的竞争条件下运行,从我的代码分析来看,它似乎来自一个不执行的延续(或者直到它结束)。
下面是一些表示上下文的伪代码:Task<Something> GetObject(string id)
{
// some async code retrieving the object
}
List<Task> tasks = new List<Task>();
List<Something> result = new List<Something>();
foreach (var id in someList)
{
tasks.Add(GetObject(id).ContinueWith(task =>
{
var something = task.Result;
// do some basic sync stuff on something
result.Add(something);
}));
}
await Task.WhenAll(tasks);
结果中随机缺少一些预期的对象。
由于某种原因,我知道foreach
运行良好,并且没有理由不将所有必需的任务添加到List<Task>
中。
检测或调试还没有给出结果,因为它似乎改善了竞争条件…我希望有人能给我点启示。谢谢!
由于某种原因,我知道每一个都很顺利,没有为什么没有将所有必需的任务添加到列表。
也许List不是线程安全的。
我不知道从你的问题,如果列表' someelist '是短或长或可能有重复的值,否则考虑添加和/或不可变列表锁。
下一个链接有一个很好的解决方案:List
List不是线程安全的。因此,如果2个线程(或更多!)想要添加元素到它,一切都可以发生(根据文档)。实际上,您可能会丢失一些添加的元素。
如果你想继续使用List,你必须自己进行同步(可能使用锁或更高级的机制)。
您还可以使用其他适合您需要的集合类型。来自System.Collections.Concurrent命名空间的类型保证是线程安全的,但当然比普通的旧List要贵一点。
最后,看起来你的例子根本不需要任何集合操作:Task.WhenAll()返回一个Task<TResult[]>
。你可以这样重写你的代码:
Something[] result;
result = await Task.WhenAll(somelist.Select(id => GetObject(id));
更短,更有效,希望更容易阅读。