通过for循环创建任务与单独创建任务不同

本文关键字:创建 任务 单独 for 通过 循环 | 更新日期: 2023-09-27 18:30:01

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

例如,这是有问题的:

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();

通过for循环创建任务与单独创建任务不同

问题是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,从i:计算temp

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();
}