Gibt es einen konzeptionellen Unterschied zwischen den folgenden zwei Codeteilen:
async Task TestAsync()
{
await Task.Run(() => DoSomeWork());
}
und
Task TestAsync()
{
return Task.Run(() => DoSomeWork());
}
Unterscheidet sich auch der generierte Code?
EDIT: Um Verwechslungen mit Task.Run
einem ähnlichen Fall zu vermeiden :
async Task TestAsync()
{
await Task.Delay(1000);
}
und
Task TestAsync()
{
return Task.Delay(1000);
}
LATE UPDATE: Zusätzlich zur akzeptierten Antwort gibt es auch einen Unterschied in der BehandlungLocalCallContext
: CallContext.LogicalGetData wird auch dann wiederhergestellt, wenn keine Asynchronität vorliegt. Warum?
c#
async-await
avo
quelle
quelle
await
async
Antworten:
Ein Hauptunterschied besteht in der Weitergabe von Ausnahmen. Eine Ausnahme, innerhalb einer geworfene
async Task
Methode wird in dem zurück gespeicherteTask
Objekt und bleibt inaktiv , bis die Aufgabe , über beobachtet wirdawait task
,task.Wait()
,task.Result
odertask.GetAwaiter().GetResult()
. Es wird auf diese Weise weitergegeben, selbst wenn es aus dem synchronen Teil derasync
Methode geworfen wird.Betrachten Sie den folgenden Code ein , wo
OneTestAsync
undAnotherTestAsync
verhalten sich ganz anders:Wenn ich anrufe
DoTestAsync(OneTestAsync, -2)
, wird die folgende Ausgabe erzeugt:Beachten Sie, ich musste drücken Enter, um es zu sehen.
Wenn ich jetzt anrufe
DoTestAsync(AnotherTestAsync, -2)
, ist der Code-Workflow im InnerenDoTestAsync
ganz anders, ebenso wie die Ausgabe. Dieses Mal wurde ich nicht gebeten zu drücken Enter:In beiden Fällen
Task.Delay(-2)
am Anfang geworfen, während die Parameter überprüft werden. Dies kann ein erfundenes Szenario sein, kann aber theoretischTask.Delay(1000)
auch auslösen, z. B. wenn die zugrunde liegende Systemzeitgeber-API ausfällt.Nebenbei bemerkt unterscheidet sich die Fehlerausbreitungslogik für
async void
Methoden (im Gegensatz zuasync Task
Methoden). Eine innerhalb einerasync void
Methode ausgelöste Ausnahme wird sofort im Synchronisationskontext des aktuellen Threads (viaSynchronizationContext.Post
) erneut ausgelöst , sofern der aktuelle Thread eine hat (SynchronizationContext.Current != null)
andernfalls wird sie via erneut ausgelöstThreadPool.QueueUserWorkItem
). Der Aufrufer hat keine Chance, diese Ausnahme auf demselben Stapelrahmen zu behandeln.Ich habe hier und hier einige weitere Details zum Verhalten bei der Behandlung von TPL-Ausnahmen veröffentlicht .
F : Ist es möglich, das Ausnahmeverbreitungsverhalten von
async
Methoden für nicht asynchroneTask
Methoden nachzuahmen , damit diese nicht auf denselben Stapelrahmen werfen?A : Wenn es wirklich gebraucht wird, gibt es dafür einen Trick:
Beachten Sie jedoch, dass die Ausführung unter bestimmten Bedingungen (z. B. wenn sie zu tief im Stapel liegt)
RunSynchronously
weiterhin asynchron ausgeführt werden kann.Ein weiterer bemerkenswerter Unterschied besteht darin, dass die Version
async
/await
anfälliger für Deadlocks in einem nicht standardmäßigen Synchronisationskontext ist . In einer WinForms- oder WPF-Anwendung wird beispielsweise Folgendes blockiert:Ändern Sie es in eine nicht asynchrone Version und es wird nicht blockiert:
Die Art der Sackgasse wird von Stephen Cleary in seinem Blog gut erklärt .
quelle
return Task.Run()
undawait Task.Run(); return
stattawait Task.Run().ConfigureAwait(false); return
Diese Frage verwirrt mich. Lassen Sie mich versuchen, dies zu klären, indem Sie Ihre Frage mit einer anderen Frage beantworten. Was ist der Unterschied zwischen?
und
?
Was auch immer der Unterschied zwischen meinen beiden Dingen ist, der gleiche Unterschied besteht zwischen Ihren beiden Dingen.
quelle
Task.Delay(1000).ContinueWith(() = {})
. Im zweiten ist es einfachTask.Delay(1000)
. Der Unterschied ist etwas subtil, aber signifikant.Die erste Methode kompiliert nicht einmal.
Es muss sein
Es gibt einen großen konzeptionellen Unterschied zwischen diesen beiden. Der erste ist asynchron, der zweite nicht. Lesen Sie Async Performance: Die Kosten von Async verstehen und warten , um mehr über die Interna von
async
/ zu erfahrenawait
.Sie generieren unterschiedlichen Code.
und
quelle
Die beiden Beispiele haben unterscheiden. Wenn eine Methode mit dem gekennzeichnet ist
async
Schlüsselwort , generiert der Compiler hinter den Kulissen eine Zustandsmaschine. Dies ist verantwortlich für die Wiederaufnahme der Fortsetzung, sobald ein Warten erwartet wurde.Wenn im Gegensatz dazu eine Methode nicht mit markiert
async
ist, verlieren Sie die Fähigkeit, zuawait
warten. (Das heißt, innerhalb der Methode selbst; die Methode kann immer noch von ihrem Aufrufer erwartet werden.) Wenn Sie jedoch dasasync
Schlüsselwort vermeiden , generieren Sie nicht mehr die Zustandsmaschine, die einiges an Overhead hinzufügen kann (das Heben von Einheimischen zu Feldern) der Zustandsmaschine, zusätzliche Objekte zum GC).Wenn Sie in Beispielen in der Lage sind,
async-await
ein Erwartetes direkt zu vermeiden und zurückzugeben, sollte dies getan werden, um die Effizienz der Methode zu verbessern.Sehen Sie sich diese Frage und diese Antwort an, die Ihrer Frage und dieser Antwort sehr ähnlich sind.
quelle