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

Task List未达预期输出,如何修复循环中Task值异常问题?

问题分析与修复方案

你遇到的这个问题,是C#里闭包捕获循环变量的经典坑!我来给你拆解原因和解决办法:

问题根源

循环中的变量i是一个共享变量,所有Task在创建时并没有立即执行,而是在后续异步调度时才会读取i的值。当Task真正开始运行时,循环大概率已经执行完毕,i已经变成了100,所以所有Task都会读取到这个最终值,导致j和cb里的内容全是100。

而逐行调试时,因为你手动控制了循环节奏,每个Task会在当前迭代时就被执行,此时i还是当前迭代的数值,所以结果正确。

修复方案

这里有两种可靠的解决办法,任选其一即可:

方案1:循环内创建局部变量捕获当前值

在每次循环迭代里,把i的值赋值给一个局部变量,让每个Task捕获这个独立的局部变量:

public static void TaskList()
{
    ConcurrentBag<int> cb = new ConcurrentBag<int>();
    List<Task> taskArray = new List<Task>();
    for (int i = 0; i < 100; i++)
    {
        // 关键:用局部变量保存当前迭代的i值
        int currentI = i;
        taskArray.Add(Task.Factory.StartNew((Object obj) => 
        {
            int j = currentI;
            cb.Add(j);
            Debug.WriteLine("Task #{0} created on {1}", j, Thread.CurrentThread.ManagedThreadId);
        }));
    }
    // 必须等待所有任务执行完成,否则程序可能提前退出导致任务未执行
    Task.WaitAll(taskArray.ToArray());
}

方案2:通过StartNew的参数传递值

利用Task.Factory.StartNew的第二个参数传递当前的i,因为参数是值传递,每个Task会拿到i的独立副本:

public static void TaskList()
{
    ConcurrentBag<int> cb = new ConcurrentBag<int>();
    List<Task> taskArray = new List<Task>();
    for (int i = 0; i < 100; i++)
    {
        // 将i作为参数传递,值传递会复制当前i的状态
        taskArray.Add(Task.Factory.StartNew((Object obj) => 
        {
            int j = (int)obj;
            cb.Add(j);
            Debug.WriteLine("Task #{0} created on {1}", j, Thread.CurrentThread.ManagedThreadId);
        }, i));
    }
    // 等待所有任务完成
    Task.WaitAll(taskArray.ToArray());
}

额外提醒

原代码里缺少了等待所有Task完成的逻辑,即使修复了闭包问题,也可能因为程序提前退出,导致部分Task还没执行就被终止,所以一定要加上Task.WaitAll来确保所有任务都执行完毕。

内容的提问来源于stack exchange,提问作者paparazzo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 10:11:02