System.Threading.Tasks for循环中的奇怪行为

时间:2013-07-05 11:19:29

标签: c# task-parallel-library

我正在for循环中创建System.Threading.Tasks,然后在同一循环中运行ContinueWith

int[,] referencedArray = new int[input.Length / 4, 5];
   for (int i = 0; i <= input.Length/4; i += 2048)
     {
       int[,] res = new int[input.Length / 4, 5];
       int[,] arrayToReference = new int[input.Length / 4, 5];
       Array.Clear(arrayToReference, 0, arrayToReference.Length);
       Array.Copy(input, i, arrayToReference, 0, input.Length / 4);
       Task<Tuple<int[,], int>> test = Task.Factory.StartNew(() => addReferences(arrayToReference, i));
        test.ContinueWith(t => { Array.Copy(t.Result.Item1, 0, referencedArray, t.Result.Item2, input.Length / 4); MessageBox.Show("yai", t.Result.Item2.ToString()); });
        Array.Copy(res, 0, referencedArray, i, input.Length / 4);

addReference sbroutine是:

public Tuple<int[,],int> addReferences(int[,] input, int index)
    {
            for (int i = 0; i < 2048; i++)
            {
                for (int j = 0; j < i; j++)
                {
                    if ((input[i, 0] == input[j, 0]) && (input[i, 1] == input[j, 1]) && (input[i, 2] == input[j, 2]) && (input[i, 3] == input[j, 3]))
                    {
                        input[i, 4] = (j - i);
                    }
                }
            }
        }
        return new Tuple<int[,],int>(input,index);
    }

然而,我得到了非常奇怪的结果:

1.索引(在任务启动时从循环计数器生成)以某种方式变得太大。我最初认为这是因为循环计数器已经增加超过其最大值,停止循环,但是当continueWith执行它时使用了新值。但是,即使我在启动时将循环计数器的值发送到任务index,错误仍然存​​在。 修改:已解决

我错误地将原始计数

2.由于某种原因,实际完成的任务少于预期(例如,即使预计会创建85个任务,基于最大160,000的循环计数器除以2,048 = 78的迭代,仅出现77个弹出窗口) - 编辑检查控制台,很明显循环计数器在突然停止之前一直运行到大约157,696。

我对“任务”和“线程”感到困惑,所以如果你能提供任何非常有用的帮助,请提前感谢。

编辑我做了Douglas建议的更改,这解决了我的第一个问题 - 我仍然坚持第二个问题。

1 个答案:

答案 0 :(得分:4)

这可能无法完全解决您遇到的问题,但作为一个起点,您需要通过将循环计数器复制到内部变量,然后在匿名方法中引用它来避免关闭问题:

for (int i = 0; i <= input.Length/4; i += 2048)
{
    // ...
    int iCopy = i;
    var test = Task.Factory.StartNew(() => addReferences(arrayToReference, iCopy));
    // ...
}

请参阅Jon Skeet's answer(特别是链接的文章),了解为何需要这样做。

编辑:关于你的第二个问题,我怀疑它可能与整数除法有关。您期望85次迭代的input.Length的值是多少?你说174,000除以2,048应该给85,但实际上它会给出84,因为整数除法会导致结果被截断。

编辑 2 :您没有看到所有预期迭代的另一个原因可能是您的程序在没有等待任务(通常在后台线程上执行)的情况下终止去完成。检查等待任务是否可以解决您的问题:

List<Task> tasks = new List<Task>();
for (int i = 0; i <= input.Length/4; i += 2048)
{
    // ...
    var test = Task.Factory.StartNew(() => addReferences(arrayToReference, iCopy));
    tasks.Add(test);
    // ...
}
Task.WaitAll(tasks);