使用async/await异步编程时为何出现结果丢失?
问题原因及修复方案
核心问题:非线程安全集合的并发冲突
你代码里的List<int> listToCollectResults是非线程安全的集合,List.Add方法并非原子操作。当100个异步任务同时执行listToCollectResults.Add(i)时,会触发竞争条件:多个线程可能同时修改List的内部结构(比如更新元素计数、写入内存位置),导致部分添加操作被覆盖,最终元素数量不足100。
另外,Thread.Sleep(1000)属于不可靠的等待方式——异步任务的调度由.NET线程池管理,极端情况下可能有任务还未完成就执行了后续的统计逻辑,但这不是你当前元素丢失的主要原因,核心矛盾还是List的线程不安全。
修复方案
方案1:使用线程安全集合
直接将List<int>替换为线程安全的ConcurrentBag<int>(适合无序场景):
private readonly ConcurrentBag<int> listToCollectResults = new();
ConcurrentBag.Add方法是线程安全的,多个任务并发调用也不会出现元素丢失。
方案2:手动加锁保护访问
如果必须使用List<int>,可以在添加元素时通过锁保证原子性:
private readonly List<int> listToCollectResults = new(); private readonly object _lockObj = new(); private async Task SleepFor250msAndAppendToListAsync(int i) { await Task.Delay(250); lock(_lockObj) { listToCollectResults.Add(i); } }
锁会确保同一时间只有一个线程能执行Add操作,避免并发冲突。
方案3:可靠等待所有任务完成(推荐)
你的代码没有正确等待异步任务完成,Thread.Sleep无法保证所有任务执行完毕。应该收集所有任务,用Task.WhenAll统一等待:
public async Task RunThisAsync() // 改为异步方法 { var tasks = new List<Task>(); for (int i = 0; i < 100; i++) { tasks.Add(SleepFor250msAndAppendToListAsync(i)); } Console.WriteLine(listToCollectResults.Count); // 预期为0 await Task.WhenAll(tasks); // 可靠等待所有任务完成 Console.WriteLine(listToCollectResults.Count); // 此时元素数量会是100(需配合线程安全集合或锁) }
这种方式能确保所有任务执行完毕后再统计数量,结合线程安全的集合操作,就能得到正确结果。
内容的提问来源于stack exchange,提问作者pe pe
相关产品推荐
相关产品推荐

