2016-10-21 2 views
3

Ich verstehe, dass Aufruf task.Result in einer async Methode zu Deadlocks führen kann. Ich habe einen anderen Twist auf die Frage, obwohl ...Ist es in Ordnung, task.Result in einer asynchronen Methode aufzurufen, wenn Sie wissen, dass die Aufgabe abgeschlossen ist?

Ich finde mich dieses Muster viel zu tun. Ich habe mehrere Aufgaben, die die gleichen Ergebnisse liefern, so dass ich sie alle gleichzeitig abwarten kann. Ich möchte die Ergebnisse separat verarbeiten, aber:

Task<int> t1 = m1Async(); 
Task<int> t2 = m2Async(); 
await Task.WhenAll(t1, t2); 

Ist es ok Result hier zu nennen, da ich die Aufgaben sind nun abgeschlossen wissen?

int result1 = t1.Result; 
int result2 = t2.Result; 

Oder sollte ich await verwenden immer noch ... es scheint überflüssig und kann ein bisschen hässlicher sein, je nachdem, wie ich brauche, um die Ergebnisse zu verarbeiten:

int result1 = await t1; 
int result2 = await t2; 

Update: markierte Jemand meine Frage als ein Duplikat von diesem: Awaiting multiple Tasks with different results. Die Frage ist anders, weshalb ich sie nicht in meinen Suchen gefunden habe, obwohl eine der detaillierten Antworten, die dort beantwortet werden, auch in Frage gestellt werden kann.

+1

Ja, es ist in Ordnung, das Ergebnis aufzurufen, wenn Sie es wissen. Wenn Sie jedoch .Result nach WhenAll aufrufen und t1 oder t2 eine Ausnahme auslösen, ist .Result problematisch. –

+0

Ich habe einige Posts gesehen, die sich auf verschiedene Verhaltensweisen mit Ausnahmen beziehen, aber ich muss noch etwas näher darauf eingehen, um alles zu verstehen. Vielen Dank für Ihre schnelle Antwort! – Cary

+0

Eine Sache, die Sie wissen sollten. Es gibt einen Leistungsüberhang beim Aufrufen von "erwarten" für eine Aufgabe, die sich bereits in dem abgeschlossenen Zustand befindet. Die Statusmaschine, die generiert wird, prüft diese Bedingung und springt einfach nach rechts, um '.Result' intern aufzurufen (sie ruft' .GetAwaiter(). GetResult() 'auf, aber sie hat denselben Overhead wie nur' .Result' aufzurufen)). Für mich gibt es also keinen zwingenden Grund, ".Result" jemals in einer Methode zu verwenden, die bereits als "async" markiert ist. –

Antwort

5

Es gibt nichts in sich falsch oder schlecht über die Verwendung t1.Result, nachdem Sie bereits eine await getan haben, aber Sie können sich für zukünftige Probleme öffnen. Was passiert, wenn jemand den Code zu Beginn Ihrer Methode ändert, sodass Sie nicht mehr sicher sein können, dass die Aufgaben erfolgreich abgeschlossen wurden? Und was, wenn sie Ihren Code nicht weiter unten sehen, der diese Annahme macht?

Scheint mir, dass es besser sein könnte, den zurückgegebenen Wert von Ihrem ersten await zu verwenden.

Task<int> t1 = m1Async(); 
Task<int> t2 = m2Async(); 
var results = await Task.WhenAll(t1, t2); 

int result1 = results[0]; 
int result2 = results[1]; 

diese Weise, wenn jemand mit den ersten await vermasselt, gibt es eine natürliche Verbindung für sie, dass der Code auf dem Ergebnis später hängt zu folgen zu wissen.

Sie können auch prüfen, ob Task.WhenAll() Ihnen wirklich einen Wert gibt. Wenn Sie nicht den Unterschied zwischen einer fehlgeschlagenen und einer fehlgeschlagenen Aufgabe unterscheiden möchten, ist es möglicherweise einfach, die Aufgaben einzeln abzuwarten.

Task<int> t1 = m1Async(); 
Task<int> t2 = m2Async(); 

int result1 = await t1; 
int result2 = await t2; 
+0

Guter Punkt mit der Rückkehr von WhenAll. Es kann jedoch haarig werden, Ergebnisse in komplizierteren Szenarien aufzustellen. Und wenn ich die Aufgaben einzeln abgehört habe, bin ich dann nicht in der Lage, die Anrufe zu serialisieren? – Cary

+2

@Cary: Sie serialisieren nur die Anrufe, wenn Sie die erste abwarten, bevor Sie die andere anrufen. Wenn Sie 'm2Async()' aufrufen, bevor Sie die Ergebnisse von 'm1Async()' 'abwarten, wird der zweite Aufruf ausgeführt, bevor Ihre Ausführung den Gültigkeitsbereich verlässt. – StriplingWarrior

Verwandte Themen