2016-05-25 12 views
0

はTPLかなり長い間を使っていて、私はまだ解決するために、いくつかの謎を持っている:)TPL - タスクが

私はコンソールでこれを実行すると、それはログに記録する前に、私はすべての作業が行われることを期待する」待望されていません「行ってジョブズ:

await StartAttachedAsync(() => 
{ 
    var result = Parallel.For(0, 4, async i => 
    { 
    CallContext.LogicalSetData("ContextId", i); 
    await Task.Run(async() => 
    { 
     await Task.Delay(2000); 
     await Task.Run(async() => 
     { 
      await Task.Delay(2000); 
      Write("Step C done for i " + i); 
     }); 
     Write("Step B done for i " + i); 
    }); 
    Write("Step A done for i " + i); 
    }); 
    Console.WriteLine("For is done: completed = " + result.IsCompleted); 
}); 
Console.WriteLine("Jobs done"); 


private static async Task StartAttachedAsync(Action action) 
{ 
    await Task.Factory.StartNew(action, 
    CancellationToken.None, 
    TaskCreationOptions.AttachedToParent, 
    TaskScheduler.Default); 
} 

は私を与える:

For loop is done: completed = True 
Jobs done 
Step C done for i 0 
Step C done for i 2 
Step C done for i 3 
Step C done for i 1 
Step B done for i 1 
Step A done for i 1 
Step B done for i 0 
Step A done for i 0 
Step B done for i 3 
Step A done for i 3 
Step B done for i 2 
Step A done for i 2 

はなぜループは、すべてのサブタスクを待たずに行われていますか?

答えて

1

待っていない本体として非同期メソッドを使用してParallel.Forを実行するためです。 基本的に何が起きるかは、火をつけて、ループ構造でタスクを忘れることです。

は、より良いあなたが作成したタスクへの参照を保持し、その後Parallel.Forを使用するためにあなたの理由は何await Task.WhenAll(tasks);

を行います。あなたはそれなしでたくさんの仕事を作り出すことができますか?

あなたの現在のコードでは、これがどうなる:

await StartAttachedAsync(() => 
{ 
    var tasks = new List<Task>(); 

    var result = Parallel.For(0, 4, async i => 
    { 
     CallContext.LogicalSetData("ContextId", i); 
     tasks.Add(Task.Run(async() => 
     { 
      await Task.Delay(2000); 
      await Task.Run(async() => 
      { 
       await Task.Delay(2000); 
       Write("Step C done for i " + i); 
      }); 
      Write("Step B done for i " + i); 
     })); 
     Write("Step A done for i " + i); 
    }); 

    await Task.WhenAll(tasks); 

    Console.WriteLine("For is done: completed = " + result.IsCompleted); 
});  
+0

実際、Parallel.For()は通常、あなたのラムダをお待ちしておりますが、ないラムダ自体が非同期である場合。とにかく、私はWhenAll()を使用しています。ありがとう – Thomas

+1

@Thomas: 'Parallel.For'は決して何かを待っていません。厳密には 'async'と互換性がありません。パラレル*および*非同期プログラミング(かなりまれです)を行う必要がある場合は、TPL Dataflowを使用してください。 –