Wann sollte ich Async-Controller in ASP.NET MVC verwenden?

215

Ich habe einige Probleme bei der Verwendung von asynchronen Aktionen in ASP.NET MVC. Wann verbessert es die Leistung meiner Apps und wann nicht ?

  1. Ist es gut, überall in ASP.NET MVC asynchrone Aktionen zu verwenden?
  2. In Bezug auf erwartete Methoden: Soll ich asynchrone / wartende Schlüsselwörter verwenden, wenn ich eine Datenbank abfragen möchte (über EF / NHibernate / anderes ORM)?
  3. Wie oft kann ich auf Schlüsselwörter warten warten, um die Datenbank in einer einzigen Aktionsmethode asynchron abzufragen ?
Vnuuk
quelle

Antworten:

109

Asynchrone Aktionsmethoden sind nützlich, wenn eine Aktion mehrere unabhängige Operationen mit langer Laufzeit ausführen muss.

Eine typische Verwendung für die AsyncController-Klasse sind lang laufende Webdienstaufrufe.

Sollten meine Datenbankaufrufe asynchron sein?

Der IIS-Thread-Pool kann häufig viel mehr gleichzeitige Blockierungsanforderungen verarbeiten als ein Datenbankserver. Wenn die Datenbank der Engpass ist, beschleunigen asynchrone Aufrufe die Datenbankantwort nicht. Ohne einen Drosselungsmechanismus wird durch die effiziente Übermittlung von mehr Arbeit an einen überlasteten Datenbankserver durch Verwendung asynchroner Aufrufe lediglich die Datenbank stärker belastet. Wenn Ihre Datenbank der Engpass ist, sind asynchrone Aufrufe nicht das Wundermittel.

Sie sollten sich 1 und 2 Referenzen ansehen

Abgeleitet von @PanagiotisKanavos Kommentaren:

Darüber hinaus bedeutet Async nicht parallel. Die asynchrone Ausführung befreit einen wertvollen Threadpool-Thread von der Blockierung für eine externe Ressource, ohne Komplexität oder Leistungskosten. Dies bedeutet, dass derselbe IIS-Computer mehr gleichzeitige Anforderungen verarbeiten kann und nicht schneller ausgeführt wird.

Sie sollten auch berücksichtigen, dass das Blockieren von Anrufen mit einem CPU-intensiven Spinwait beginnt. In Stresszeiten führt das Blockieren von Anrufen zu eskalierenden Verzögerungen und zum Recycling von App-Pools. Asynchrone Aufrufe vermeiden dies einfach

Tharif
quelle
27
In Bezug auf Async, IIS und die Datenbank ist der Blog-Beitrag extrem alt und die hier gezogenen Schlussfolgerungen sind falsch. IIS muss eine viel größere Last als die Datenbank ausrichten, Threadpool-Threads sind begrenzt und eine lange Anforderungswarteschlange kann zu 500 führen. Alles, was einen Thread freigibt, während auf E / A gewartet wird, ist von Vorteil. Auch in den Links geht es nicht darum, was das OP gefragt hat. In der Tat haben die gleichen Autoren geschrieben , dass Sie sollten asynchrone DB - Methoden verwenden , wo immer Sie können
Panagiotis Kanavos
30
Darüber hinaus bedeutet Async nicht parallel. Die asynchrone Ausführung befreit einen wertvollen Threadpool-Thread von der Blockierung für eine externe Ressource, ohne Komplexität oder Leistungskosten. Das bedeutet , die gleiche IIS Maschine verarbeiten kann mehr gleichzeitige Zugriffe, nicht , dass es schneller laufen.
Panagiotis Kanavos
5
Sie sollten auch berücksichtigen, dass das Blockieren von Anrufen mit einem CPU-intensiven Spinwait beginnt. In Stresszeiten führt das Blockieren von Anrufen zu eskalierenden Verzögerungen und zum Recycling von App-Pools. Asynchrone Anrufe vermeiden dies einfach
Panagiotis Kanavos
1
Da dies die akzeptierte Antwort ist und daher für die meisten Menschen ganz oben steht, ist es möglicherweise ratsam, den zweiten ersten Absatz bezüglich der Ausführungszeiten und der parallelen Ausführung zu entfernen, was nichts mit Asynchronität zu tun hat. Mir ist klar, dass es am Ende eine Notiz gibt, aber sie ist ziemlich irreführend.
Rob
1
Die asynchrone Ausführung gibt einen Thread nur dann frei, wenn er bis zum Ende der Implementierung wirklich asynchron ist, und verwendet einen Rückrufmechanismus, um die Bereitschaft zu signalisieren und einen neuen Thread zu starten, um den Kontext zu wechseln und das Ergebnis zu verarbeiten. Ich bin mir also nicht sicher, in welchen Fällen dieser Kontextwechsel / die Erstellung neuer Threads effizienter ist, als nur auf Ergebnisse in einem einzelnen Thread zu warten. Lang laufende Webdienstanrufe sind sowieso eine schlechte Idee. Ich ziehe es vor, sie an einen zuverlässigen Hintergrunddienst auszulagern und den Client nach Ergebnissen suchen zu lassen, die in wenigen Minuten, Stunden oder Tagen eintreten können.
JustAMartin
229

Möglicherweise finden Sie meinen MSDN-Artikel zu diesem Thema hilfreich . Ich nahm viel Platz in diesem Artikel beschreiben , wenn Sie sollten verwenden asyncauf ASP.NET, nicht nur , wie die Verwendung asyncauf ASP.NET.

Ich habe einige Probleme bei der Verwendung von asynchronen Aktionen in ASP.NET MVC. Wann verbessert es die Leistung meiner Apps und wann - nicht.

Verstehe zunächst, dass es bei async/ awaitdarum geht , Threads freizugeben . Bei GUI-Anwendungen geht es hauptsächlich darum , den GUI-Thread freizugeben, damit die Benutzererfahrung besser wird. Bei Serveranwendungen (einschließlich ASP.NET MVC) geht es hauptsächlich darum , den Anforderungsthread freizugeben, damit der Server skalieren kann.

Insbesondere wird es nicht:

  • Machen Sie Ihre individuellen Anfragen schneller. Tatsächlich werden sie (nur ein kleines bisschen) langsamer abgeschlossen.
  • Kehren Sie zum Anrufer / Browser zurück, wenn Sie eine drücken await. await"ergibt" nur dem ASP.NET-Thread-Pool, nicht dem Browser.

Die erste Frage lautet: Ist es gut, überall in ASP.NET MVC asynchrone Aktionen zu verwenden?

Ich würde sagen, es ist gut, es überall dort zu verwenden, wo Sie E / A ausführen. Dies muss jedoch nicht unbedingt von Vorteil sein (siehe unten).

Es ist jedoch schlecht , es für CPU-gebundene Methoden zu verwenden. Manchmal denken Entwickler, dass sie die Vorteile nutzen können, asyncindem sie einfach Task.Runihre Controller anrufen , und das ist eine schreckliche Idee. Da dieser Code den Anfragethread durch Aufnehmen eines anderen Threads freigibt, gibt es überhaupt keinen Vorteil (und tatsächlich werden zusätzliche Thread-Schalter bestraft)!

Soll ich asynchrone / warte Schlüsselwörter verwenden, wenn ich eine Datenbank abfragen möchte (über EF / NHibernate / anderes ORM)?

Sie können alle verfügbaren Methoden verwenden, die Ihnen zur Verfügung stehen. Im Moment unterstützen die meisten Hauptakteure async, aber es gibt einige, die dies nicht tun. Wenn Ihr ORM dies nicht unterstützt async, versuchen Sie nicht, es einzupacken Task.Runoder ähnliches (siehe oben).

Beachten Sie, dass ich sagte "Sie könnten verwenden". Wenn Sie über ASP.NET MVC mit einem einzigen Datenbank-Backend sprechen, werden Sie (mit ziemlicher Sicherheit) keinen Vorteil in Bezug auf die Skalierbarkeit erzielen async. Dies liegt daran, dass IIS weitaus mehr gleichzeitige Anforderungen verarbeiten kann als eine einzelne Instanz von SQL Server (oder einem anderen klassischen RDBMS). Allerdings, wenn Ihr Backend modernere ist - eine SQL - Server - Cluster, Azure SQL, NoSQL, usw. - und Backend können skaliert und Ihre Skalierbarkeit Engpass ist IIS, dann können Sie von einer Skalierbarkeit profitieren zu bekommen async.

Dritte Frage - Wie oft kann ich auf Schlüsselwörter warten warten, um die Datenbank in EINER einzelnen Aktionsmethode asynchron abzufragen?

So viele wie du willst. Beachten Sie jedoch, dass viele ORMs eine Regel für eine Operation pro Verbindung haben. Insbesondere erlaubt EF nur eine einzige Operation pro DbContext; Dies gilt unabhängig davon, ob die Operation synchron oder asynchron ist.

Beachten Sie auch die Skalierbarkeit Ihres Backends. Wenn Sie auf eine einzelne Instanz von SQL Server zugreifen und Ihr IIS bereits in der Lage ist, SQLServer auf voller Kapazität zu halten, hilft es Ihnen überhaupt nicht, den Druck auf SQLServer zu verdoppeln oder zu verdreifachen.

Stephen Cleary
quelle
2
@seebiscuit: Bei (ordnungsgemäßer asynchroner) E / A werden keine Threads verwendet. Ich habe einen Blog-Beitrag , der ausführlicher behandelt wird.
Stephen Cleary
2
Wie viele Anforderungen können IIS und eine einzelne SQL Server-Instanz verarbeiten? Wie finde ich diese Nummern?
MOD
1
@MOD: Das hängt von der Konfiguration und der Hardware ab. Die einzige Möglichkeit, diese Nummern zu finden, besteht darin, einen Auslastungstest auf Ihrem eigenen Server durchzuführen.
Stephen Cleary
1
@Flezcano: Methoden, die vollständig auf der CPU ausgeführt werden. Das heißt, sie führen keine E / A oder Blockierungen durch.
Stephen Cleary
1
Tut mir leid, Sir, aber SO werde ich diese 2-Liner-Frage nicht akzeptieren, die ich zu verstehen versuche. Wenn ich nach dieser Sache gesucht habe, wie wenn ich 1 Web-API-Endpunkt habe, der von 1000 Benutzern gleichzeitig aufgerufen wird, dann wird dieser Endpunkt in der Lage sein um jede dieser tausend Anfragen zu bedienen, oder sollte ich es asynchron machen, 1000 Anfragen zu bearbeiten?
Learning-Overthinker-Confused
21

Ist es gut, überall in ASP.NET MVC asynchrone Aktionen zu verwenden?

Wie bei der Programmierung üblich, kommt es darauf an . Es gibt immer einen Kompromiss, wenn Sie einen bestimmten Weg gehen.

async-awaitleuchtet an Orten, an denen Sie wissen, dass Sie gleichzeitig Anfragen an Ihren Service erhalten und in der Lage sein möchten, eine gute Skalierung vorzunehmen . Wie async-awaithilft beim Skalieren? Wenn Sie einen asynchronen E / A-Aufruf synchron aufrufen , z. B. einen Netzwerkaufruf oder Ihre Datenbank, wird der aktuelle Thread, der für die Ausführung verantwortlich ist, blockiert, bis die Anforderung beendet ist. Wenn Sie verwenden async-await, aktivieren Sie das Framework, um eine Zustandsmaschine für Sie zu erstellen, die sicherstellt, dass Ihre Methode nach Abschluss des E / A-Aufrufs dort ausgeführt wird, wo sie aufgehört hat.

Zu beachten ist, dass diese Zustandsmaschine einen subtilen Overhead hat. Wenn eine Methode asynchron gemacht wird, wird sie nicht schneller ausgeführt. Dies ist ein wichtiger Faktor zum Verstehen und ein Missverständnis, das viele Menschen haben.

Eine andere Sache , unter Berücksichtigung zu nehmen , wenn mit async-awaitder Tatsache ist , dass es async den ganzen Weg , was bedeutet , dass Sie werden sehen , async Ihre gesamte Call - Stack, von oben nach unten nach einzudringen. Dies bedeutet, dass Sie, wenn Sie synchrone APIs verfügbar machen möchten, häufig eine bestimmte Menge an Code duplizieren, da Async und Sync nicht sehr gut zusammenpassen.

Soll ich asynchrone / warte Schlüsselwörter verwenden, wenn ich eine Datenbank abfragen möchte (über EF / NHibernate / anderes ORM)?

Wenn Sie sich für die Verwendung von asynchronen E / A-Aufrufen entscheiden, ist Ja async-awaiteine gute Wahl, da immer modernere Datenbankanbieter eine asynchrone Methode zur Implementierung des TAP (Task Asynchronous Pattern) bereitstellen.

Wie oft kann ich Schlüsselwörter zum Warten verwenden, um die Datenbank in EINER einzelnen Aktionsmethode asynchron abzufragen?

So viele Sie möchten, solange Sie die von Ihrem Datenbankanbieter festgelegten Regeln befolgen. Die Anzahl der asynchronen Anrufe, die Sie tätigen können, ist unbegrenzt. Wenn Sie Abfragen haben, die unabhängig voneinander sind und gleichzeitig ausgeführt werden können, können Sie für jede eine neue Aufgabe drehen und await Task.WhenAllwarten, bis beide abgeschlossen sind.

Yuval Itzchakov
quelle
2
Asynchrone Datenbankaufrufe werden nicht schneller ausgeführt, sondern ermöglichen es demselben IIS-Computer, viel mehr Anforderungen zu bedienen, da Threadpool-Threads nicht verschwendet werden. Es senkt auch die CPU-Kosten, da das Blockieren von Anrufen tatsächlich mit einem CPU-intensiven Spinwait beginnt, bevor es tatsächlich blockiert wird. In Situationen mit hoher Last kann dies der Unterschied zwischen dem Kämpfen oder Versagen der Maschine und dem Recycling sein
Panagiotis Kanavos
@PanagiotisKanavos Ich weiß, war das unklar von dem, was ich gesagt habe?
Yuval Itzchakov
1
In Ihrer Antwort werden die IIS-Besonderheiten nicht erwähnt - das Meltdown / Recycle-Szenario ist ein Hauptgrund für die Verwendung von Async. Jemand, der es nicht nicht erlebt wohl verstehen , dass scale out wellbedeuten kann your server won't die under load. Oder es kann ein Fall vononce burned ...
Panagiotis Kanavos
7

Meine 5 Cent:

  1. Verwenden async/awaitSie diese Option nur dann, wenn Sie eine E / A-Operation ausführen, z. B. DB oder externer Service-Webservice.
  2. Bevorzugen Sie immer asynchrone Aufrufe an DB.
  3. Jedes Mal, wenn Sie die Datenbank abfragen.

PS Es gibt Ausnahmefälle für Punkt 1, aber Sie müssen dafür ein gutes Verständnis der asynchronen Interna haben.

Als zusätzlichen Vorteil können Sie bei Bedarf nur wenige E / A-Aufrufe parallel ausführen:

Task task1 = FooAsync(); // launch it, but don't wait for result
Task task2 = BarAsync(); // launch bar; now both foo and bar are running
await Task.WhenAll(task1, task2); // this is better in regard to exception handling
// use task1.Result, task2.Result
bohdan_trotsenko
quelle
6

asyncAktionen helfen am besten, wenn die Aktionen einige E / A-Vorgänge für die Datenbank oder einige netzwerkgebundene Aufrufe ausführen, bei denen der Thread, der die Anforderung verarbeitet, blockiert wird, bevor er von der DB oder dem netzwerkgebundenen Aufruf, den Sie gerade aufgerufen haben, beantwortet wird. Es ist am besten, wenn Sie mit ihnen warten, und es wird die Reaktionsfähigkeit Ihrer Anwendung wirklich verbessern (da weniger ASP-Eingabe- / Ausgabe-Threads blockiert werden, während auf die Datenbank oder eine andere Operation wie diese gewartet wird). In all meinen Anwendungen, wenn viele Aufrufe an DB sehr notwendig sind, habe ich sie immer in eine awaiatable-Methode eingeschlossen und diese mit einem awaitSchlüsselwort aufgerufen .

Dimitri
quelle
5

Wie Sie wissen, unterstützt MVC asynchrone Controller, und Sie sollten dies nutzen. Wenn Ihr Controller einen längeren Vorgang ausführt (es kann sich um eine festplattenbasierte E / A oder einen Netzwerkaufruf an einen anderen Remotedienst handeln), ist der IIS-Thread die ganze Zeit beschäftigt, wenn die Anforderung synchron verarbeitet wird. Infolgedessen wartet der Thread nur darauf, dass der lange Vorgang abgeschlossen ist. Es kann besser genutzt werden, indem andere Anforderungen bedient werden, während die zuerst angeforderte Operation ausgeführt wird. Dies hilft bei der Bearbeitung von mehr gleichzeitigen Anfragen. Ihr Webservice ist hoch skalierbar und kann nicht leicht auf ein C10k-Problem stoßen . Es ist eine gute Idee, async / await für Datenbankabfragen zu verwenden. und ja, Sie können sie so oft verwenden, wie Sie es für richtig halten.

Schauen Sie hier nach exzellenten Ratschlägen.

Anurag
quelle
3

Ich habe die Erfahrung gemacht, dass heutzutage viele Entwickler async/awaitals Standard für Controller verwenden.

Mein Vorschlag wäre, es nur zu verwenden, wenn Sie wissen, dass es Ihnen helfen wird .

Der Grund dafür ist, dass, wie Stephen Cleary und andere bereits erwähnt haben, Leistungsprobleme auftreten können, anstatt sie zu lösen, und dass dies nur in einem bestimmten Szenario hilfreich ist:

  • Controller mit hohem Verkehrsaufkommen
  • Skalierbares Backend
Gajama
quelle
2

Ist es gut, überall in ASP.NET MVC asynchrone Aktionen zu verwenden?

Dies ist überall dort sinnvoll, wo Sie eine asynchrone Methode verwenden können, insbesondere wenn Leistungsprobleme auf der Ebene der Arbeitsprozesse auftreten, die bei umfangreichen Daten- und Berechnungsvorgängen auftreten. Andernfalls ist dies nicht erforderlich, da beim Testen von Einheiten ein Guss erforderlich ist.

In Bezug auf erwartete Methoden: Soll ich asynchrone / wartende Schlüsselwörter verwenden, wenn ich eine Datenbank abfragen möchte (über EF / NHibernate / anderes ORM)?

Ja, es ist besser, Async für jeden DB-Vorgang so weit wie möglich zu verwenden, um Leistungsprobleme auf der Ebene der Arbeitsprozesse zu vermeiden. Beachten Sie, dass EF für die meisten Vorgänge viele asynchrone Alternativen erstellt hat, z.

.ToListAsync()
.FirstOrDefaultAsync()
.SaveChangesAsync()
.FindAsync()

Wie oft kann ich auf Schlüsselwörter warten warten, um die Datenbank in einer einzigen Aktionsmethode asynchron abzufragen?

Der Himmel ist die Grenze

Shadi Namrouti
quelle
Die Geschäftslogik für die meisten Webanwendungen erfordert normalerweise sehr sequentielle Vorgänge. Daher ist das Wechseln zwischen parallelen Prozessen in den meisten Fällen nur auf der obersten Ebene der Verwaltung von Webanfragen / Arbeitsprozessen möglich, die Datenbankanforderungen ohnehin nicht direkt verarbeitet. Ich möchte wirklich einige Beispiele aus der Praxis einer typischen Webanwendung sehen, bei denen es eigentlich eine gute Idee wäre, DB-Abfragen asynchron zu verarbeiten.
JustAMartin