2014-04-16 10 views
15

Das folgende Snippet kompiliert, aber ich würde erwarten, dass es auf das Task-Ergebnis wartet, anstatt mir eine List<Task<T>> zu geben.Was passiert eigentlich, wenn in einer LINQ-Anweisung async/wait verwendet wird?

var foo = bars.Select(async bar => await Baz(bar)).ToList() 

Wie bereits ausgeführt here, müssen Sie Task.WhenAll verwenden:

var tasks = foos.Select(async foo => await DoSomethingAsync(foo)).ToList(); 
await Task.WhenAll(tasks); 

Aber a comment weist darauf hin, dass die async und await innerhalb des Select() ist nicht erforderlich:

var tasks = foos.Select(foo => DoSomethingAsync(foo)).ToList(); 

Ein ähnliches Frage here wo jemand versucht, eine asynchrone Methode in einem verwenden Where().

Also async und await innerhalb einer LINQ-Anweisung ist rechtliche Syntax, aber tut es überhaupt nichts oder hat es eine bestimmte Verwendung?

Antwort

21

Ich empfehle, dass Sie dies nicht als "mit async in LINQ". Denken Sie daran, was dazwischen liegt: Delegierte. Mehrere LINQ-Operatoren nehmen Delegaten und async kann verwandt werden, um einen asynchronen Delegaten zu erstellen.

Also, wenn Sie eine asynchrone Methode haben BazAsync, dass die Renditen ein Task:

Task BazAsync(TBar bar); 

dann dieser Code führt zu einer Abfolge von Aufgaben:

IEnumerable<Task> tasks = bars.Select(bar => BazAsync(bar)); 

Und falls Sie verwenden async und await Innerhalb des Delegaten erstellen Sie einen asynchronen Delegaten, der eine Task:

zurückgibt 210
IEnumerable<Task> tasks = bars.Select(async bar => await BazAsync(bar)); 

Diese beiden LINQ-Ausdrücke sind funktional äquivalent. Es gibt keine wichtigen Unterschiede.

Genau wie normale LINQ-Ausdrücke wird die IEnumerable<Task> Lazy-evaluated. Nur, mit asynchronen Methoden wie BazAsync, tun Sie normalerweise nicht wollen versehentliche Doppel-Bewertung oder ähnliches.Wenn Sie also auf eine Abfolge von Aufgaben projizieren, ist es normalerweise eine gute Idee, die Sequenz sofort zu bestätigen. Dies erfordert BazAsync für alle Elemente in der Quellsequenz, die alle Aufgaben gehen Start:

Task[] tasks = bars.Select(bar => BazAsync(bar)).ToArray(); 

Natürlich alles, was wir mit Select getan haben ist für jedes Element ein asynchroner Vorgang starten. Wenn Sie für sie alle zu vervollständigen warten wollen, dann Task.WhenAll verwenden:

await Task.WhenAll(tasks); 

Die meisten anderen LINQ-Operatoren arbeiten nicht so sauber mit asynchronen Delegierten. Select ist ziemlich einfach: Sie starten gerade eine asynchrone Operation für jedes Element.

+0

"Es gibt keine wichtigen Unterschiede." - Wenn BazAsync synchron auslöst und das nicht asynchrone Lambda bei der Enumeration und Verwendung des asynchronen Lambdas verwendet wird, geschieht dies, während die Tasks abgewartet werden. –

+1

@EliArbel: Ja. Aber eine asynchrone synchrone Methode ist ein sehr ungewöhnlicher Fall. Async-Methoden sollten * nur * Sync-Ausnahmen auslösen, wenn sie [boneheaded Ausnahmen] sind (https://blogs.msdn.microsoft.com/ericlippert/2008/09/10/vexing-exceptions/). Daher halte ich das für keinen wichtigen Anwendungsfall. –

+1

verfassen - https://en.wikipedia.org/wiki/Retification_(computer_science) – BozoJoe

4

hat es eine bestimmte Verwendung

Sicher. Mit async und erwarten Sie in einer LINQ-Anweisung können Sie z. so etwas tun:

var tasks = foos.Select(async foo => 
    { 
     var intermediate = await DoSomethingAsync(foo); 
     return await DoSomethingElseAsync(intermediate); 
    }).ToList(); 
await Task.WhenAll(tasks); 

Ohne async/erwarten in einer LINQ-Anweisung sind Sie nicht alles, was in der LINQ-Anweisung wartet, so dass Sie das Ergebnis nicht verarbeiten, oder warten auf etwas anderes.

Ohne async/await starten Sie in der LINQ-Anweisung nur Aufgaben, warten jedoch nicht darauf, dass sie abgeschlossen werden. Sie werden immer noch abgeschlossen, aber es wird passieren, lange nachdem das Steuerelement die LINQ-Anweisung verlassen wird, so dass Sie nur auf ihre Ergebnisse zugreifen können, nachdem die WhenAll Zeile abgeschlossen ist, aber nicht innerhalb der LINQ-Anweisung.

Verwandte Themen