当我运行以下操作时,我得到任务#{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("");
}
答案 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
我不确定我是否做了很好的解释,但我希望它有所帮助。