3

for ループ内から作成してから、同じループ内でSystem.Threading.Tasksa を実行しています。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.何らかの理由で、予想よりも少ないタスクが実際に完了します (たとえば、最大 160,000 のループ カウンターを 2,048 = 78 の反復で割ると、85 のタスクが作成されると予想されますが、77 のポップアップしか表示されません) -編集チェックコンソールを見ると、ループ カウンターが約 157,696 まで上がってから突然停止したことがわかります。

Tasks と Threading については本当に混乱しています。

編集ダグラスが提案した変更を加えました。これにより、最初の問題が解決されました.2番目の問題はまだ解決していません。

4

1 に答える 1

4

これで問題が完全に解決されるわけではありませんが、出発点として、匿名メソッドでループ カウンターを参照する前に内部変数にループ カウンターをコピーして、クロージャの問題を回避する必要があります。

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

これが必要な理由の説明については、Jon Skeet の回答(特にリンクされた記事) を参照してください。

編集:2番目の問題に関しては、整数除算に関係していると思われます。85回の反復を期待している の値はinput.Length? 174,000 を 2,048 で割ると 85 になるはずですが、実際には 84 になります。これは、整数除算によって結果が切り捨てられるためです。

編集2 : 予想されるすべての反復が表示されないもう 1 つの理由は、タスク (通常はバックグラウンド スレッドで実行される) が完了するのを待たずにプログラムが終了している可能性があります。タスクを待機することで問題が解決するかどうかを確認します。

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);
于 2013-07-05T11:24:53.037 に答える