Ich bin mir bewusst, wie Async auf Arbeit wartet. Ich weiß, dass, wenn die Ausführung wartet, es den Thread freigibt, und nachdem IO abgeschlossen ist, ruft es den Thread aus dem Threadpool ab und führt den verbleibenden Code aus. Auf diese Weise werden Threads effizient genutzt. Aber ich bin in einigen Anwendungsfällen verwirrt:
Sollen wir asynchrone Methoden für die sehr schnelle IO-Methode verwenden, wie die Cache-Lese- / Schreibmethode?
Ein solches IO würde nicht im klassischen Sinne blockieren. "Blockieren" ist ein lose definierter Begriff. Normalerweise bedeutet dies, dass die CPU auf die Hardware warten muss.
Diese Art von IO ist reine CPU-Arbeit und es gibt keine Kontextwechsel. Dies würde normalerweise passieren, wenn die App eine Datei oder einen Socket langsamer liest, als Daten bereitgestellt werden können. Hier hilft async IO überhaupt nicht. Ich bin nicht einmal sicher, ob es geeignet wäre, den UI-Thread zu entsperren, da alle Aufgaben synchron ablaufen könnten.
Oder es spart auch CPU?
Im Allgemeinen erhöht es die CPU-Auslastung in realen Lasten. Dies liegt daran, dass die asynchrone Maschinerie Verarbeitung, Zuordnungen und Synchronisation hinzufügt. Außerdem müssen wir zweimal statt nur einmal in den Kernelmodus wechseln (zuerst, um die IO zu initiieren und dann die IO-Abschlussbenachrichtigung zu entfernen).
Typische Workloads laufen mit & lt; & lt; 100% CPU. Ein Produktionsserver mit & gt; 60% CPU würde mich beunruhigen, da kein Spielraum für Fehler besteht. In solchen Fällen sind die Threadpool-Arbeitswarteschlangen fast immer leer. Daher gibt es keine Conversion-Switch-Einsparungen, die durch die Verarbeitung mehrerer E / A-Vervollständigungen für einen Kontextwechsel verursacht werden.
Aus diesem Grund erhöht sich die CPU-Auslastung im Allgemeinen (geringfügig), es sei denn, der Rechner ist sehr stark ausgelastet und die Arbeitswarteschlangen können häufig sofort einen neuen Artikel liefern.
Auf dem Server ist async IO hauptsächlich zum Speichern von Threads nützlich. Wenn Sie genügend Threads verfügbar haben, werden Sie Null oder negative Gewinne realisieren. Insbesondere wird jedes einzelne IO nicht ein bisschen schneller werden.
Das heißt, es verbraucht keine CPU.
Es wäre eine Verschwendung, die CPU nicht verfügbar zu haben, während ein IO läuft. Für den Kernel ist ein IO nur eine Datenstruktur. Während es läuft, gibt es keine CPU-Arbeit zu tun.
Eine anonyme Person sagte:
Für E / A-gebundene Tasks kann die Verwendung separater Threads keinen großen Leistungsvorteil bedeuten, nur um auf ein Ergebnis zu warten.
Die gleiche Arbeit zu einem anderen Thread zu schieben hilft sicherlich nicht mit dem Durchsatz. Dies ist hinzugefügt Arbeit, nicht reduzierte Arbeit. Es ist ein Shell-Spiel. (Und async IO verwendet keinen Thread, während es ausgeführt wird, also basiert alles auf einer falschen Annahme.)
Eine einfache Möglichkeit, sich selbst davon zu überzeugen, dass Async-IO im Allgemeinen mehr CPU kostet als Sync-IO, um eine einfache TCP-Ping / Pong-Benchmark-Synchronisierung und Async auszuführen. Die Synchronisierung ist schneller. Dies ist eine Art künstlicher Ladung, also ist es nur ein Hinweis auf das, was vor sich geht und keine umfassende Messung.
Ich bin mir bewusst, wie Async auf Arbeit wartet.
Sie sind nicht.
Ich weiß, dass die Ausführung des Threads
freigegeben wird, wenn die Ausführung erreicht ist
Es tut es nicht. Wenn die Ausführung eine Wartezeit erreicht, wird der erwartete Operand ausgewertet, und dann wird geprüft, ob die Operation abgeschlossen ist. Wenn dies nicht der Fall ist, wird der Rest der Methode als Fortsetzung des Erwarteten angemeldet, und eine Aufgabe, die die Arbeit der aktuellen Methode darstellt, wird an den Aufrufer zurückgegeben.
Nichts davon ist "den Thread loslassen". Stattdessen kehrt control zum Aufrufer zurück und der Aufrufer führt die Ausführung im aktuellen Thread fort. Wenn der aktuelle Aufrufer das einzige in diesem Thread ist, ist der Thread natürlich erledigt. Aber es ist nicht erforderlich, dass eine asynchrone Methode der einzige Aufruf für einen Thread ist!
nachdem IO abgeschlossen ist
Ein erwartetes muss keine IO-Operation sein, aber nehmen wir an, dass es das ist.
ruft Thread aus threadpool ab und führt den verbleibenden Code aus.
Nein. It plant den verbleibenden Code für die Ausführung im richtigen Kontext . Dieser Kontext könnte ein Threadpool-Thread sein. Es könnte der UI-Thread sein. Es könnte der aktuelle Thread sein. Es könnte eine beliebige Anzahl von Dingen sein.
Sollen wir asynchrone Methoden für die sehr schnelle IO-Methode verwenden, wie die Cachespeicher-Lese- / Schreibmethode?
Das Erwartete wird ausgewertet. Wenn der Erwartete weiß, dass er den Vorgang in einer angemessenen Zeit abschließen kann, ist es vollkommen in seinem Recht, den Vorgang auszuführen und eine abgeschlossene Aufgabe zurückzugeben. In diesem Fall gibt es keine Strafe; Sie überprüfen nur einen booleschen Wert, um zu sehen, ob die Aufgabe abgeschlossen ist.
Würden sie nicht unnötig zu einem Kontextwechsel führen?
Nicht unbedingt.
Wenn wir die sync-Methode verwenden, wird die Ausführung auf demselben Thread abgeschlossen, und ein Kontextwechsel kann nicht stattfinden.
Ich bin verwirrt, warum Sie glauben, dass ein Kontextwechsel bei einer IO-Operation passiert. IO-Operationen werden auf Hardware unterhalb der Ebene der OS-Threads ausgeführt. Da ist kein Thread da, der IO-Aufgaben erledigt.
Schreibt Async-wait nur die Speicherbelegung (durch Erstellen kleinerer Threads)
Der Zweck von hazard besteht darin, (1) teure Worker-Threads effizienter zu nutzen, indem Workflows asynchroner werden und dadurch Threads für die Arbeit freigegeben werden, während auf Ergebnisse mit hoher Latenz gewartet wird, und (2) zu machen Der Quellcode für asynchrone Workflows ähnelt dem Quellcode für synchrone Workflows.
Soweit ich weiß, wird im Falle von Sync IO, während IO stattfindet, der Thread in den Schlafmodus versetzt. Das heißt, es verbraucht keine CPU. Ist dieses Verständnis korrekt?
Klar, aber du hast das komplett rückwärts. Sie möchten CPU verbrauchen . Sie möchten so viel CPU wie möglich konsumieren! Die CPU macht arbeiten im Auftrag des Benutzers und wenn sie im Leerlauf ist , wird ihre Arbeit nicht so schnell erledigt wie sie könnte. Setze keinen Arbeiter ein und bezahle sie dann zum Schlafen! Stellen Sie einen Mitarbeiter ein, und sobald sie bei einer Aufgabe mit hoher Latenz blockiert sind, setzen Sie sie ein, um etwas anderes zu tun , damit die CPU die ganze Zeit so heiß wie möglich bleibt. Der Besitzer dieser Maschine bezahlte gutes Geld für diese CPU; es sollte die ganze Zeit, in der es Arbeit gibt, zu 100% laufen!
Kommen wir nun zu Ihrer grundlegenden Frage zurück:
Erh? ht Async wartet, erh? ht Kontextwechsel?
Ich kenne einen guten Weg, das herauszufinden. Schreiben Sie ein Programm mit awarna, schreiben Sie ein anderes ohne, führen Sie beide aus und messen Sie die Anzahl der Kontextwechsel pro Sekunde. Dann wirst du es wissen.
Aber ich sehe nicht, warum Kontextwechsel pro Sekunde eine relevante Metrik ist. Betrachten wir zwei Banken mit vielen Kunden und vielen Mitarbeitern. Bei Bank Nr. 1 arbeiten die Mitarbeiter an einer Aufgabe, bis sie abgeschlossen ist. Sie wechseln nie den Kontext. Wenn ein Mitarbeiter beim Warten auf ein Ergebnis von einem anderen blockiert ist, gehen sie schlafen. Bei Bank # 2 wechseln die Mitarbeiter bei Blockierung von einer Aufgabe zur anderen und kümmern sich ständig um Kundenanfragen. Welche Bank hat Ihrer Meinung nach einen schnelleren Kundendienst?
Tags und Links c# multithreading async-await asynchronous