是否通过for循环创建任务与单独创建它们不同?

时间:2013-09-03 20:59:43

标签: c# parallel-processing task-parallel-library

我遇到的问题似乎与任务创建有关。在使用循环填充任务数组并在单独的循环中启动它之后,我的结果虽然一致,但却是错误的。但是,如果我单独填充数组,在循环内启动每个任务,一切都很好。任何人都可以给我一些建议吗?

例如,这是有问题的:

int c = 1;
for (int i = 1; i <= 4; i++)
    {
       taskArray[i-1] = new Task(() => calculateRows(c, true));
       c = c + 2;
    }
foreach (Task t in taskArray) t.Start();

但这很好用:

taskArray[0] = new Task(() => calculateRows(1, true));
taskArray[1] = new Task(() => calculateRows(3, true));
taskArray[2] = new Task(() => calculateRows(5, true));
taskArray[3] = new Task(() => calculateRows(7, true));
foreach (Task t in taskArray) t.Start();

1 个答案:

答案 0 :(得分:6)

问题是你的lambda表达式捕获c - 变量 c,而不是它在创建任务时的值。所以当你开始执行任务时,c将是9.即使你在循环中启动它们,仍然无法保证lambda表达式中的代码将开始执行之前对c的更改。

要解决此问题,您可以为循环的每次迭代使用单独的局部变量:

int c = 1;
for (int i = 1; i <= 4; i++)
{
    int temp = c;
    taskArray[i-1] = new Task(() => calculateRows(temp, true));
    c = c + 2;
}
foreach (Task t in taskArray)
{
    t.Start();
}

或完全绕过c并从temp计算i

for (int i = 1; i <= 4; i++)
{
    int temp = i * 2 - 1;
    taskArray[i-1] = new Task(() => calculateRows(temp, true));
}
foreach (Task t in taskArray)
{
    t.Start();
}

你是否需要将这些全部作为单独的任务?您可以使用Parallel.For吗?或者可能是评论中建议的Enumerable.Range

var tasks = Enumerable.Range(1, 4)
                      .Select(x => new Task(() => calculateRows(x * 2 - 1, true)
                      .ToArray();
foreach (Task t in tasks)
{
    t.Start();
}