2016-05-25 11 views
0

benutze tpl eine ganze Weile gewartet, und ich habe noch ein paar Geheimnisse zu lösen haben :)TPL - Aufgabe ist nicht

Wenn ich dies in einer Konsole laufen, würde ich erwarten, dass alle Arbeit getan werden, bevor er meldet " Jobs "getan:

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); 
} 

mich gibt:

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 

Warum die Schleife ohne warten auf alle Teilaufgaben erledigt ist?

Antwort

1

Da Sie eine Parallel.For mit einer asynchronen Methode als Körper ausführen, die nicht erwartet wird. Also im Grunde, was passiert ist, starten Sie einige Feuer und vergessen Sie Aufgaben in einem Schleifenkonstrukt.

halten Bessere einen Verweis auf die Aufgaben, die Sie erstellen und dann eine await Task.WhenAll(tasks);

Was Sie Grund ist Parallel.For zu verwenden. Kannst du nicht einfach eine Reihe von Aufgaben erstellen?

In Ihrem aktuellen Code wird dies tun:

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

Tat Parallel.For() normalerweise erwartet Ihr Lambda, aber nicht, wenn das Lambda-Asynchron an mir ist. Ich benutze WhenAll() jetzt sowieso. Danke – Thomas

+1

@Thomas: 'Parallel.Für' nie' erwarten 's alles; es ist streng inkompatibel mit Async. Wenn Sie parallele * und * asynchrone Programmierung durchführen müssen (was eher selten ist), verwenden Sie TPL Dataflow. –