8

C# 5 と .Net 4.5 で非同期プログラミングを学び始めましたが、理解できないことがあります。

private static int count;

public static void Main()
{
    LoopTest();

    Console.ReadKey(false);
}

static async void LoopTest()
{
    count = 0;

    for (var index = 0; index < 10; ++index)
    {
        Console.WriteLine( "({0}) In Loop before await, Index {1}, Thread: {2}", count++, index, Thread.CurrentThread.ManagedThreadId);
        await Task.Factory.StartNew(() => Thread.Sleep(10));
    }
}

結果は次のとおりです。

 (0) In Loop before await, Index 0, Thread: 9  
 (1) In Loop before await, Index 1, Thread: 10    
 (2) In Loop before await, Index 2, Thread: 11   
 (3) In Loop before await, Index 3, Thread: 10  
 (4) In Loop before await, Index 4, Thread: 11  
 (5) In Loop before await, Index 5, Thread: 10  
 (6) In Loop before await, Index 6, Thread: 12  
 (7) In Loop before await, Index 7, Thread: 11  
 (8) In Loop before await, Index 8, Thread: 10  
 (9) In Loop before await, Index 9, Thread: 12

同じループにアクセスする異なるスレッドがありますか? インデックス変数に競合状態はありますか?

4

2 に答える 2

13

いいえ、競合状態はありません。バックグラウンドで実行される新しいタスクを開始しますが、コードはそのタスクが終了するまで続行されないため、コードが一度に 1 つのスレッドでのみ実行されることを確認できます。

ただし、これはコンソール アプリケーションであるため、最新のSyncronizationContext. (Winform、WPF、ASP、Silverlight などのアプリケーションとは異なります。) これは、呼び出しからの継続がawait、呼び出し元のスレッドではなく、スレッド プールで実行されることを意味します。そうです、あなたはループの各反復でスレッド プール スレッドの 1 つで実行されており、毎回異なるものになる可能性がありますが、新しいタスク内に入れるものを除いて、"次の作業を開始する前に、特定のスレッドで「finish」を実行することで、特定の時点でコードを実行するスレッドが 1 つだけになるようにします (競合状態がないことを意味します)。

于 2013-01-17T15:01:21.967 に答える
4

あなたがしていることは本当に非同期ではありません

await Task.Factory.StartNew(() => Thread.Sleep(10));

これにより、タスクが作成され、そのタスクが完了するまで待機します。ここで Thread.Sleep(10) を呼び出すだけでもかまいません。

これを行うためのより適切な方法は次のとおりです。

Task myTask = Task.Factory.StartNew(() => Thread.Sleep(10));
... do stuff here ...
await myTask; // Now wait for the task to complete

ループで多数のタスクを実行したい場合は、Parallel.Foreach()メソッドを確認する必要があります。

于 2013-01-17T14:54:50.990 に答える