任务列表没有给我我的期望

时间:2018-05-01 22:31:57

标签: c# .net task

当我运行以下操作时,我得到任务#{0}和cb

的值为100

如果我在循环中逐行调试,那么我会得到正确答案。

如何解决这个问题?

public static void TaskList()
{
    ConcurrentBag<int> cb = new ConcurrentBag<int>();
    List<Task> taskArray = new List<Task>();
    for (int i = 0; i < 100; i++)
    {
        taskArray.Add(Task.Factory.StartNew((Object obj) => {
            int j = 0 + i;
            cb.Add(j);
            Debug.WriteLine("Task #{0} created on {1}",
                                j, Thread.CurrentThread.ManagedThreadId);
            Thread.Sleep(10);
        },
                                                i));
    }
    Task.WaitAll(taskArray.ToArray());
    foreach(var v in cb)
    {
        Debug.WriteLine(v);
    }
    Debug.WriteLine("");
}

2 个答案:

答案 0 :(得分:3)

您正在任务中传递修改后的闭包(i)。

当有效执行Task时,i的值未确定(在您的情况下,它是100,因为任务在for循环结束后开始)。

你必须避免捕获懒惰执行的委托内的修改后的闭包(你的Task片段就是一个例子,但IEnumerable上的LINQ可能会发生同样的情况。)

相反,请将您的值分配给局部变量并将其传递到Task操作中:

for (int i = 0; i < 100; i++)
{
    var count = i;
    taskArray.Add(Task.Factory.StartNew((Object obj) => {
        int j = 0 + count;
        cb.Add(j);
        Debug.WriteLine("Task #{0} created on {1}",
                            j, Thread.CurrentThread.ManagedThreadId);
        Thread.Sleep(10);
    },
                                            i));
}

答案 1 :(得分:1)

您看到100几乎每次运行都会打印出来,因为以下行中的i在任务运行时相当于100:

int j = 0 + i;

我相信您尝试使用int j = 0 + i行缓解此问题,但由于i正在改变,j仍将始终等同于{{1}是任务运行的时候。如果您将i的值分配给任务的<{1}} ,那么您将看不到此问题:

i

我不确定我是否做了很好的解释,但我希望它有所帮助。