为什么使用任务时集合无法正确填充?



我有一段非常简单的代码:

public class CustomTester
{
public async Task RunTheTestAsync()
{
IList<int> someCollectionToFill = new List<int>();
var someCollectionToIterate = Enumerable.Range(0, 20);
IEnumerable<Task> tasks = someCollectionToIterate.Select(
valueFromCollection => Task.Run(async () =>
{
try
{
await Task.Delay(1);
someCollectionToFill.Add(valueFromCollection);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
})).ToList();
await Task.WhenAll(tasks);
PrintCollectionValues(someCollectionToFill);
}
private void PrintCollectionValues(IList<int> collection)
{
Console.WriteLine("Total count: " + collection.Count);
}
}

我是这样执行的:

await new CustomTester().RunTheTestAsync();

当代码执行时,有如下输出:

Total count: 13

或:

Total count: 14

等等……

但我期待:

Total count: 20

为什么会发生这种情况?

你正在使用一个列表,一个非线程安全的集合,并发地来自多个线程。这样不安全。使用

lock(someCollectionToFill){
someCollectionToFill.Add(valueFromCollection);
}

var someCollectionToFill = new ConcurrentBag<int>();

我强烈建议在尝试使用任何多线程之前阅读线程安全。多线程最佳实践是一个良好的开端,但它并没有涵盖所有内容,所以我建议您在谷歌上搜索一下。编写多线程代码是很困难的,而且很容易犯错误,导致间歇性的错误,这些错误很难调试和理解。

最新更新