You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 19:32:37