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

为何多Task执行时函数参数值混乱,结果出现大量重复?

问题原因分析

1. 错误共享值类型实例(或闭包延迟绑定问题)

你的代码存在一个核心错误:直接通过ExampleStruct类型访问实例字段number和otherData(代码里写成zip是笔误)。C#中值类型(struct)的实例字段必须通过具体实例访问,强行通过类型访问时,编译器会隐式创建一个静态默认实例,所有Task都会共享这个实例的字段值。

循环中你不断修改这个共享实例的number值,但Task.Run是异步执行的——当Task真正启动执行GetDataFor时,循环可能已经跑完最后一次迭代(i=999),所以大部分Task都会读取到最后设置的999。

退一步说,即便你创建了局部实例,在旧版C#(C#5之前)的for循环中,闭包是引用捕获循环内的变量,所有Task会指向同一个变量引用,最终也会导致多数Task拿到最后一次循环的值。

2. List非线程安全引发竞争条件

List<T>的Add方法没有线程安全保护,多个Task同时调用results.Add()时会出现竞争:比如两个线程同时写入列表同一位置,或列表扩容时内部状态不一致,这会导致元素被覆盖、丢失,最终出现重复值或缺失值。

修复方案

步骤1:创建独立实例并正确捕获

在循环内部创建专属的struct实例,确保每个Task拿到当前迭代的独立数据。C#5及以后版本中,循环内声明的局部变量会在每次迭代时创建新实例,直接使用即可:

for(int i = 0; i < 1000; i++)
{
    ExampleStruct data = new ExampleStruct();
    data.number = i.ToString();
    data.otherData = "3333";
    TList.Add(Task.Run(() => GetDataFor(data)).ContinueWith(ct => incrementProgress(worker)));
}

步骤2:改用线程安全集合

用ConcurrentBag<string>(适用于无序场景)替代List<string>,它内置线程安全机制,避免并发写入的竞争问题:

// 替换原List<string>
ConcurrentBag<string> results = new ConcurrentBag<string>();

private void GetDataFor(ExampleStruct dataInput)
{
    results.Add(dataInput.number.ToString());
}

完整修复代码示例

public struct ExampleStruct
{
    public string number;
    public string otherData;
}

ConcurrentBag<string> results = new ConcurrentBag<string>();
List<Task> TList = new List<Task>();

void mainFunc()
{
    // 如果要1-1000,将i的起始值改为1,循环条件改为i<=1000
    for(int i = 0; i < 1000; i++)
    {
        ExampleStruct data = new ExampleStruct();
        data.number = i.ToString();
        data.otherData = "3333";
        TList.Add(Task.Run(() => GetDataFor(data)).ContinueWith(ct => incrementProgress(worker)));
    }
    Task.WaitAll(TList.ToArray());
    // 此时results包含0-999所有值,顺序可能无序,但每个值仅出现一次
}

private void GetDataFor(ExampleStruct dataInput)
{
    results.Add(dataInput.number.ToString());
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 21:40:36