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