将非参考值传递给Task

时间:2012-04-11 22:53:06

标签: c# parallel-processing task

将int变量传递给任务时,我经常得到奇怪的结果:例如:

List<List<object>> ListToProcess = new List<List<object>>();

// place some lists in list to process
foreach (var temp in Foo)
    ListToProcess.Add(temp);

foreach (var tempArray in ListToProcess)
{
    // initialize each list in ListToProcess                    
}

int numberOfChunks = ListToProcess.Count; 
Task[] tasks = new Task[numberOfChunks];
for (int counter = 0; counter < numberOfChunks; counter++)
{
    tasks[counter] = Task.Factory.StartNew(() =>
        {
            // counter is always = 5  why?   <---------------------------
            var t = ListToProcess[counter];                        
        });
}

我该如何解决这个问题?

4 个答案:

答案 0 :(得分:3)

这被称为闭包。您没有使用变量的值,您正在使用变量本身。代码执行时,它使用执行时的值,而不是定义任务时的值。

要解决这个问题,我相信你会做这样的事情:

for (int counter = 0; counter < numberOfChunks; counter++)
{
    int cur = counter;
    tasks[counter] = Task.Factory.StartNew(() =>
    {
        // counter is always = 5  why?   <---------------------------
        var t = ListToProcess[cur];                        
    });
}

答案 1 :(得分:1)

无法保证何时访问StartNew的Action块中的'counter'变量。可能发生的是,循环所有5个值,并创建任务,然后安排任务运行。

当它们运行时,执行以下操作:

var t = ListToProcess[counter];

但在这个阶段,计数已经等于5。

也许您应该看看并行集合?

ListToProcess.AsParallel().ForAll(list => dosomething(list));

该地区还有很多其他选择。

答案 2 :(得分:0)

    for (int counter = 0; counter < numberOfChunks; counter++)
    {
        var referenceVariable = new{val=counter};
        tasks[counter] = Task.Factory.StartNew(() =>
            {
                var t = ListToProcess[referenceVariable.val];                        
            });
    }

答案 3 :(得分:0)

由于捕获了变量,您可以通过在每个循环中重新声明一个新变量来解决此问题。

for (int counter = 0; counter < numberOfChunks; counter++)
{
    int localCounter = counter;
    tasks[localCounter] = Task.Factory.StartNew(() =>
        {
            // counter is always = 5  why?   <---------------------------
            var t = ListToProcess[localCounter];                        
        });
}