Ich bin auf einige Best Practices für die asynchrone Programmierung mit c # s async/ awaitkeywords 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 awaitdort auch verwenden, wie Toni vorschlägt.]