Ich bin auf einige Best Practices für die asynchrone Programmierung mit c # s async
/ await
keywords gestoßen (ich bin neu in c # 5.0).
Einer der gegebenen Ratschläge war der folgende:
Stabilität: Kennen Sie Ihre Synchronisationskontexte
... Einige Synchronisationskontexte sind nicht wiedereintrittsfähig und Single-Threaded. Dies bedeutet, dass jeweils nur eine Arbeitseinheit im Kontext ausgeführt werden kann. Ein Beispiel hierfür ist der Windows-UI-Thread oder der ASP.NET-Anforderungskontext. In diesen Single-Threaded-Synchronisationskontexten ist es einfach, sich selbst zu blockieren. Wenn Sie eine Aufgabe aus einem Single-Thread-Kontext heraus erzeugen und dann im Kontext auf diese Aufgabe warten, blockiert Ihr Wartecode möglicherweise die Hintergrundaufgabe.
public ActionResult ActionAsync()
{
// DEADLOCK: this blocks on the async task
var data = GetDataAsync().Result;
return View(data);
}
private async Task<string> GetDataAsync()
{
// a very simple async method
var result = await MyWebService.GetDataAsync();
return result.ToString();
}
Wenn ich versuche, es selbst zu zerlegen, wird der Haupt-Thread zu einem neuen in MyWebService.GetDataAsync();
, aber da der Haupt-Thread dort wartet, wartet er auf das Ergebnis in GetDataAsync().Result
. In der Zwischenzeit sagen wir, die Daten sind fertig. Warum setzt der Hauptthread seine Fortsetzungslogik nicht fort und gibt ein Zeichenfolgenergebnis von zurück GetDataAsync()
?
Kann mir bitte jemand erklären, warum es im obigen Beispiel einen Deadlock gibt? Ich habe keine Ahnung, wo das Problem liegt ...
var data = GetDataAsync().Result;
ist eine Codezeile, die niemals in einem Kontext ausgeführt werden sollte, den Sie nicht blockieren sollten (UI- oder ASP.NET-Anforderung). Selbst wenn es nicht blockiert, blockiert es den Thread auf unbestimmte Zeit. Im Grunde ist es ein schreckliches Beispiel. [Sie müssen den UI-Thread verlassen, bevor Sie solchen Code ausführen, oder await
dort auch verwenden, wie Toni vorschlägt.]