运行以下命令时,任务#{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("");
}发布于 2018-05-01 22:54:56
您正在任务中传递一个修改的闭包(i)。
当有效执行Task时,不确定i的值(在您的情况下,它是100,因为任务在for循环完成后开始)。
您必须避免在延迟执行的委托中捕获修改过的闭包(您的Task片段就是一个例子,但使用LINQonIEnumerable也可能发生同样的情况)。
相反,将值赋值给局部变量,并将其传递到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));
}发布于 2018-05-01 22:55:03
在几乎每次运行时,您都会看到100被打印出来,因为下面一行中的i在任务运行时相当于100:
int j = 0 + i;我相信您正在尝试用int j = 0 + i行来缓解这个问题,但是由于i是要更改的,所以j仍然等同于任务运行时的i。如果在任务之外将i的值分配给j,则不会看到这个问题:
int j = i;
taskArray.Add(Task.Factory.StartNew((Object obj) => {
cb.Add(j);
Console.WriteLine("Task #{0} created on {1}",
j, Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(10);
}, , i));我不确定我在解释这个问题上做得很好,但我希望这会有所帮助。
https://stackoverflow.com/questions/50124755
复制相似问题