2015-06-13 3 views
7

Ich versuche Task.WaitAll auf einer Liste von Aufgaben zu verwenden. Die Sache ist, die Aufgaben sind ein asynchrones Lambda, das Tasks.WaitAll bricht, wie es nie wartet. HierTask.Factory.StartNew mit async Lambda und Task.WaitAll

ist ein Beispiel Codeblock:

List<Task> tasks = new List<Task>(); 
tasks.Add(Task.Factory.StartNew(async() => 
{ 
    using (dbContext = new DatabaseContext()) 
    { 
     var records = await dbContext.Where(r => r.Id = 100).ToListAsync(); 
     //do long cpu process here... 
    } 
} 
Task.WaitAll(tasks); 
//do more stuff here 

Dieses wartet nicht wegen der Asynchron-Lambda. Wie soll ich also auf I/O-Operationen in meinem Lambda warten?

+0

Was den Punkt des Ausgangs ist eine Aufgabe in einem anderen Thread, wenn das erste, was Sie tun, nachdem Sie es gestartet haben, Block auf dem 'Task.WaitAll' Aufruf ist? Sie erhalten eine bessere Leistung, indem Sie 'ToListAsync' loswerden und es nur' ToList' machen und es synchron laufen lassen. (oder wenn Sie 'ToListAsync' verwenden wollen, dann müssen Sie Async ganz nach oben in Ihrem Call-Stack verwenden. –

Antwort

10

Task.Factory.StartNew erkennt nicht async Delegierten, da es keine Überlastung, die eine Funktion eines Task Rückkehr akzeptiert.

Dieses Plus anderen Gründen (siehe StartNew is dangerous) ist, warum Sie Task.Run hier verwendet werden soll:

tasks.Add(Task.Run(async() => ... 
+0

Das hat funktioniert ... irgendwie. Ich bin mir nicht sicher, ob das Problem jetzt auftritt, aber ich bekomme eine Aufgabe abgebrochen Einen anderen String zurückgeben, also werde ich einen neuen SO-Thread starten. Danke. –

+2

Schade Task.run gibt Ihnen nicht 'TaskCreationOptions' –

+0

'Task.Factory.StartNew (Func function' scheint in .NET Standard 1 verfügbar sein.6 - man könnte die resultierende 'Aufgabe' though'() '( – urbanhusky

-1

müssen Sie die Task.ContinueWith Methode verwenden. Gefällt Ihnen dieses

List<Task> tasks = new List<Task>(); 
tasks.Add(Task.Factory.StartNew(() => 
{ 
    using (dbContext = new DatabaseContext()) 
    { 
     return dbContext.Where(r => r.Id = 100).ToListAsync().ContinueWith(t => 
      { 
       var records = t.Result; 
       // do long cpu process here... 
      }); 
     } 
    } 
} 
0

Sie können wie folgt tun.

void Something() 
    { 
     List<Task> tasks = new List<Task>(); 
     tasks.Add(ReadAsync()); 
     Task.WaitAll(tasks.ToArray()); 
    } 

    async Task ReadAsync() { 
     using (dbContext = new DatabaseContext()) 
     { 
      var records = await dbContext.Where(r => r.Id = 100).ToListAsync(); 
      //do long cpu process here... 
     } 
    } 
+0

) auspacken (wrappen) müssen. Das war fast eine gute Antwort. Sie sollten nicht auf "Task.WaitAll" blockieren, wenn Sie Async verwenden, da Sie leicht Deadlock können. –

+0

WaitAll ist, was Jacob nach der Frage machen wollte. – hebinda

9

Dieses wartet nicht wegen der Asynchron-Lambda. Also wie soll ich E/A-Operationen in meinem Lambda warten?

Der Grund Task.WaitAll für den Abschluss der Arbeiten IO nicht von Ihrem async Lambda präsentiert warten, weil Task.Factory.StartNew tatsächlich eine Task<Task> zurückgibt. Da Ihre Liste ist List<Task> (und Task<T> leitet sich von Task ab), warten Sie auf die äußere Aufgabe von StartNew gestartet, während ignoriert die innere eine erstellt von der asynchronen Lambda. Deshalb sagen sie Task.Factory.StartNew ist gefährlich in Bezug auf Async.

Wie können Sie das beheben? Sie könnten explizit Task<Task>.Unwrap() aufrufen, um die innere Aufgabe zu erhalten:

List<Task> tasks = new List<Task>(); 
tasks.Add(Task.Factory.StartNew(async() => 
{ 
    using (dbContext = new DatabaseContext()) 
    { 
     var records = await dbContext.Where(r => r.Id = 100).ToListAsync(); 
     //do long cpu process here... 
    } 
}).Unwrap()); 

Oder wie andere gesagt, könnte man Task.Run stattdessen nennen:

tasks.Add(Task.Run(async() => /* lambda */); 

Auch da Sie das Recht, Dinge zu tun sein wollen, Sie ‚ll will Task.WhenAll verwenden, warum ist asynchron wartbar, statt Task.WaitAll, die synchron Blöcke:

await Task.WhenAll(tasks);