Ich lese gerade " Concurrency in C # Cookbook " von Stephen Cleary und habe die folgende Technik bemerkt:
var completedTask = await Task.WhenAny(downloadTask, timeoutTask);
if (completedTask == timeoutTask)
return null;
return await downloadTask;
downloadTask
ist ein Aufruf an httpclient.GetStringAsync
und timeoutTask
wird ausgeführt Task.Delay
.
Falls es keine Zeitüberschreitung gab, downloadTask
ist es bereits abgeschlossen. Warum muss eine Sekunde gewartet werden, anstatt zurückzukehren downloadTask.Result
, da die Aufgabe bereits abgeschlossen ist?
c#
asynchronous
async-await
task
julio.g
quelle
quelle
downloadTask
undtimeoutTask
? Was machen Sie?AggregateException
mitResult
vs erster Ausnahme überExceptionDispatchInfo
mitawait
). Ausführlicher besprochen in Stephen Toubs "Task Exception Handling in .NET 4.5": blogs.msdn.com/b/pfxteam/archive/2011/09/28/… )Antworten:
Es gibt hier bereits einige gute Antworten / Kommentare, aber nur um ...
Es gibt zwei Gründe , warum ich es vorziehen ,
await
überResult
(oderWait
). Das erste ist, dass die Fehlerbehandlung unterschiedlich ist;await
schließt die Ausnahme nicht in einAggregateException
. Im Idealfall sollte asynchroner Code niemals behandelt werden müssenAggregateException
, es sei denn, er möchte dies ausdrücklich .Der zweite Grund ist etwas subtiler. Wie ich in meinem Blog (und im Buch) beschreibe, kann
Result
/Wait
Deadlocks verursachen und bei Verwendung in einerasync
Methode noch subtilere Deadlocks verursachen . Wenn ich also Code durchlese und einResult
oder seheWait
, ist das eine sofortige Warnflagge. DasResult
/Wait
ist nur dann korrekt, wenn Sie absolut sicher sind, dass die Aufgabe bereits abgeschlossen ist. Dies ist nicht nur auf einen Blick schwer zu erkennen (im realen Code), sondern es ist auch spröder, Codeänderungen vorzunehmen.Das ist nicht zu sagen
Result
/Wait
sollte niemals verwendet werden. Ich folge diesen Richtlinien in meinem eigenen Code:await
.Result
/ verwenden,Wait
wenn der Code dies wirklich erfordert. Eine solche Verwendung sollte wahrscheinlich Kommentare enthalten.Result
und verwendenWait
.Beachten Sie, dass (1) bei weitem der häufigste Fall ist, daher meine Tendenz,
await
überall zu verwenden und die anderen Fälle als Ausnahmen von der allgemeinen Regel zu behandeln.quelle
await
verhindert denAggregateException
Wrapper.AggregateException
wurde für die parallele Programmierung entwickelt, nicht für die asynchrone Programmierung.Wait
war die Verknüpfung mit Instanzen für dynamische AufgabenparallelitätTask
. Das Warten auf asynchroneTask
Instanzen ist gefährlich. Microsoft erwog die Einführung eines neuen "Promise" -Typs, entschied sich jedoch dafür,Task
stattdessen den vorhandenen zu verwenden. Der Nachteil der Wiederverwendung des vorhandenenTask
Typs für asynchrone Aufgaben besteht darin, dass Sie am Ende mehrere APIs haben, die im asynchronen Code einfach nicht verwendet werden sollten.Dies ist sinnvoll, wenn
timeoutTask
es sich um ein Produkt handelt, vonTask.Delay
dem ich glaube, dass es in dem Buch steht.Task.WhenAny
Gibt zurückTask<Task>
, wobei die innere Aufgabe eine der Aufgaben ist, die Sie als Argumente übergeben haben. Es könnte so umgeschrieben werden:In beiden Fällen gibt es, da
downloadTask
bereits abgeschlossen, einen sehr geringen Unterschied zwischenreturn await downloadTask
undreturn downloadTask.Result
. Es ist so, dass letzterer wirft,AggregateException
was jede ursprüngliche Ausnahme umschließt, wie @KirillShlenskiy in den Kommentaren hervorhob. Ersteres würde nur die ursprüngliche Ausnahme erneut auslösen.In beiden Fällen sollten Sie, wo immer Sie Ausnahmen behandeln, nach
AggregateException
und nach den inneren Ausnahmen suchen, um zur Fehlerursache zu gelangen.quelle