Ich versuche, die async/await
Funktion von ASP.NET in meinem Web-API-Projekt zu verwenden. Ich bin mir nicht sicher, ob sich dies auf die Leistung meines Web-API-Dienstes auswirkt. Nachfolgend finden Sie den Workflow und den Beispielcode aus meiner Bewerbung.
Arbeitsablauf:
UI-Anwendung → Web-API-Endpunkt (Controller) → Aufrufmethode in der Web-API-Serviceschicht → Rufen Sie einen anderen externen Webdienst auf. (Hier haben wir die DB-Interaktionen usw.)
Regler:
public async Task<IHttpActionResult> GetCountries()
{
var allCountrys = await CountryDataService.ReturnAllCountries();
if (allCountrys.Success)
{
return Ok(allCountrys.Domain);
}
return InternalServerError();
}
Serviceschicht:
public Task<BackOfficeResponse<List<Country>>> ReturnAllCountries()
{
var response = _service.Process<List<Country>>(BackOfficeEndpoint.CountryEndpoint, "returnCountries");
return Task.FromResult(response);
}
Ich habe den obigen Code getestet und funktioniert. Ich bin mir aber nicht sicher, ob es die richtige Verwendung von ist async/await
. Bitte teilen Sie Ihre Gedanken.
Antworten:
Beachten Sie, dass der Hauptvorteil von asynchronem Code auf der Serverseite die Skalierbarkeit ist . Es wird Ihre Anfragen nicht auf magische Weise beschleunigen.
async
In meinem Artikel überasync
ASP.NET gehe ich auf einige Überlegungen ein, die ich verwenden sollte .Ich denke, Ihr Anwendungsfall (Aufruf anderer APIs) eignet sich gut für asynchronen Code. Denken Sie jedoch daran, dass "asynchron" nicht "schneller" bedeutet. Der beste Ansatz besteht darin, Ihre Benutzeroberfläche zunächst reaktionsschnell und asynchron zu gestalten. Dadurch fühlt sich Ihre App schneller an, auch wenn sie etwas langsamer ist.
Was den Code betrifft, ist dies nicht asynchron:
Sie benötigen eine wirklich asynchrone Implementierung, um die Skalierbarkeitsvorteile von
async
:Oder (wenn Ihre Logik in dieser Methode wirklich nur ein Durchgang ist):
Beachten Sie, dass es einfacher ist, von innen nach außen zu arbeiten, als von außen nach innen. Mit anderen Worten, beginnen Sie nicht mit einer asynchronen Controller-Aktion und erzwingen Sie dann, dass nachgeschaltete Methoden asynchron sind. Identifizieren Sie stattdessen die natürlich asynchronen Vorgänge (Aufrufen externer APIs, Datenbankabfragen usw.) und machen Sie diese zuerst auf der untersten Ebene asynchron (
Service.ProcessAsync
). Lassen Sie dann dasasync
Rinnsal hoch und machen Sie Ihre Controller-Aktionen als letzten Schritt asynchron.Und unter keinen Umständen sollten Sie
Task.Run
in diesem Szenario verwenden.quelle
Es ist richtig, aber vielleicht nicht nützlich.
Da es nichts zu warten gibt - keine Aufrufe zum Blockieren von APIs, die asynchron arbeiten könnten -, richten Sie Strukturen ein, um den asynchronen Betrieb (mit Overhead) zu verfolgen, nutzen diese Funktion jedoch nicht.
Wenn die Serviceschicht beispielsweise DB-Vorgänge mit Entity Framework ausführt, das asynchrone Aufrufe unterstützt:
Sie würden dem Worker-Thread erlauben, etwas anderes zu tun, während die Datenbank abgefragt wurde (und somit eine andere Anforderung verarbeiten können).
Warten ist in der Regel etwas, das den ganzen Weg nach unten gehen muss: Es ist sehr schwierig, es in ein bestehendes System nachzurüsten.
quelle
Sie nutzen async / await nicht effektiv, da der Anforderungsthread beim Ausführen der synchronen Methode blockiert wird
ReturnAllCountries()
Der Thread, der für die Bearbeitung einer Anfrage zugewiesen ist, wartet während
ReturnAllCountries()
der Arbeit im Leerlauf .Wenn Sie
ReturnAllCountries()
asynchron implementieren können, sehen Sie Vorteile für die Skalierbarkeit. Dies liegt daran, dass der Thread möglicherweise wieder in den .NET-Thread-Pool freigegeben wird, um eine andere Anforderung zu verarbeiten, während erReturnAllCountries()
ausgeführt wird. Dies würde Ihrem Dienst einen höheren Durchsatz ermöglichen, indem Threads effizienter genutzt werden.quelle
Ich würde Ihre Serviceschicht ändern in:
So wie Sie es haben, führen Sie Ihren
_service.Process
Anruf immer noch synchron aus und profitieren nur sehr wenig oder gar nicht davon, darauf zu warten.Mit diesem Ansatz verpacken Sie den potenziell langsamen Anruf in a
Task
, starten ihn und geben ihn zurück, damit er erwartet wird. Jetzt haben Sie den Vorteil, auf das zu wartenTask
.quelle
Service
ist keine asynchrone Methode und wird imService
Aufruf selbst nicht erwartet . Ich kann seinen Standpunkt verstehen, aber ich glaube nicht, dass er hier zutrifft.Task.Run
sollte unter ASP.NET vermieden werden. Dieser Ansatz würde alle Vorteile vonasync
/ entfernenawait
und unter Last eine schlechtere Leistung erzielen als nur ein synchroner Anruf.