Warum wird Multithreading oft bevorzugt, um die Leistung zu verbessern?

23

Ich habe eine Frage, es geht darum, warum Programmierer Nebenläufigkeit und Multithread-Programme im Allgemeinen zu lieben scheinen.

Ich betrachte hier zwei Hauptansätze:

  • Ein asynchroner Ansatz, der im Wesentlichen auf Signalen basiert, oder einfach nur ein asynchroner Ansatz, wie er von vielen Veröffentlichungen und Sprachen, wie beispielsweise dem neuen C # 5.0, aufgerufen wird, und ein "Begleitthread", der die Richtlinien Ihrer Pipeline verwaltet
  • ein gleichzeitiger Ansatz oder ein Multithreading-Ansatz

Ich möchte nur sagen, dass ich über die Hardware hier und das Worst-Case-Szenario nachdenke und diese beiden Paradigmen selbst getestet habe. Das asynchrone Paradigma ist ein Gewinner, wenn ich nicht verstehe, warum die Leute in 90% der Fälle Sprechen Sie über Multithreading, wenn Sie Dinge beschleunigen oder Ihre Ressourcen optimal nutzen möchten.

Ich habe Multithread- und Async-Programme auf einer alten Maschine mit einem Intel Quad-Core getestet, die keinen Speichercontroller in der CPU bietet. Der Speicher wird vollständig vom Motherboard verwaltet Multithread-Anwendung, auch eine relativ geringe Anzahl von Threads wie 3-4-5 kann ein Problem sein, die Anwendung reagiert nicht und ist nur langsam und unangenehm.

Ein guter asynchroner Ansatz ist andererseits wahrscheinlich nicht schneller, aber er ist auch nicht schlechter. Meine Anwendung wartet nur auf das Ergebnis und hängt nicht, sie reagiert und es findet eine viel bessere Skalierung statt.

Ich habe auch herausgefunden, dass eine Kontextänderung in der Threading-Welt im realen Szenario nicht so billig ist, sondern in der Tat ziemlich teuer, insbesondere wenn mehr als zwei Threads zum Berechnen zyklisch und untereinander ausgetauscht werden müssen.

Bei modernen CPUs ist die Situation nicht wirklich anders, der Speichercontroller ist integriert. Mein Punkt ist jedoch, dass eine x86-CPU im Grunde eine serielle Maschine ist und der Speichercontroller genauso funktioniert wie bei der alten Maschine mit einem externen Speichercontroller auf dem Motherboard . Der Kontextwechsel ist nach wie vor ein erheblicher Kostenfaktor in meiner Anwendung und die Tatsache, dass der Speichercontroller integriert ist oder dass die neuere CPU mehr als 2 Kerne hat, ist für mich kein Schnäppchen.

Für das, was ich erlebt habe, ist der gleichzeitige Ansatz in der Theorie gut, aber in der Praxis nicht so gut. Mit dem von der Hardware auferlegten Speichermodell ist es schwierig, dieses Paradigma gut zu nutzen, und es wirft auch eine Menge Probleme auf, die von der Verwendung reichen meiner Datenstrukturen zum Join mehrerer Threads.

Auch bieten beide Paradigmen keine Sicherheit, wenn die Aufgabe oder die Arbeit zu einem bestimmten Zeitpunkt erledigt wird, was sie vom funktionalen Standpunkt aus wirklich ähnlich macht.

Warum schlägt die Mehrheit der Benutzer laut X86-Speichermodell vor, die Parallelität mit C ++ und nicht nur einen asynchronen Ansatz zu verwenden? Warum nicht auch das Worst-Case-Szenario eines Computers in Betracht ziehen, bei dem der Kontextwechsel wahrscheinlich teurer ist als die Berechnung selbst?

user1849534
quelle
2
Ein Vergleich wäre, sich die JavaScript-Welt anzuschauen, wenn es kein Threading gibt und alles mithilfe von Rückrufen aggressiv asynchron ist. Es funktioniert, aber es hat seine eigenen Probleme.
Gort the Robot
2
@StevenBurnap Wie nennt man Web Worker?
user16764
2
"Selbst eine relativ geringe Anzahl von Threads wie 3-4-5 kann ein Problem sein, die Anwendung reagiert nicht und ist nur langsam und unangenehm." => Möglicherweise liegt es an einem schlechten Design / einer unangemessenen Verwendung von Threads. In der Regel tritt eine solche Situation auf, wenn Ihre Threads weiterhin Daten austauschen. In diesem Fall ist Multi-Threading möglicherweise nicht die richtige Antwort, oder Sie müssen die Daten möglicherweise neu partitionieren.
Assylias
1
@assylias Wenn eine deutliche Verlangsamung des UI-Threads festgestellt wird, weist dies auf eine übermäßige Sperrung der Threads hin. Entweder haben Sie eine schlechte Implementierung oder Sie versuchen, einen quadratischen Stift in ein rundes Loch zu schlagen.
Evan Plaice
5
Sie sagen, "Programmierer scheinen Nebenläufigkeit und Multithread-Programme im Allgemeinen zu lieben". Das bezweifle ich. Ich würde sagen "Programmierer hassen es" ... aber oft ist es das einzig Nützliche ...
Johannes

Antworten:

34

Sie haben mehrere Kerne / Prozessoren, verwenden Sie diese

Async eignet sich am besten für die Verarbeitung starker E / A-Bindungen, aber wie steht es mit der Verarbeitung starker CPU- Bindungen ?

Das Problem tritt auf, wenn Singlethread-Codeblöcke in einem Prozess mit langer Laufzeit hängen bleiben. Denken Sie beispielsweise daran, dass beim Drucken eines Textverarbeitungsdokuments die gesamte Anwendung eingefroren wird, bis der Auftrag gesendet wurde. Das Einfrieren von Anwendungen ist eine Nebenwirkung des Blockierens von Anwendungen mit einem Thread während einer CPU-intensiven Aufgabe.

In einer Multithread-Anwendung können CPU-intensive Aufgaben (z. B. ein Druckauftrag) an einen Hintergrund-Worker-Thread gesendet werden, wodurch der UI-Thread freigegeben wird.

In einer Multiprozessanwendung kann der Auftrag ebenfalls per Messaging (z. B. IPC, Sockets usw.) an einen Subprozess gesendet werden, der speziell für die Verarbeitung von Aufträgen entwickelt wurde.

In der Praxis haben Async- und Multithread- / Prozesscode jeweils Vor- und Nachteile.

Sie können den Trend in den wichtigsten Cloud-Plattformen beobachten, da sie Instanzen anbieten, die auf CPU-gebundene Verarbeitung und auf IO-gebundene Verarbeitung spezialisiert sind.

Beispiele:

  • Speicher (ab Amazon S3, Google Cloud Drive) ist CPU-gebunden
  • Webserver sind IO-gebunden (Amazon EC2, Google App Engine)
  • Datenbanken sind sowohl CPU-gebunden zum Schreiben / Indizieren als auch IO-gebunden zum Lesen

Um es in die richtige Perspektive zu rücken ...

Ein Webserver ist ein perfektes Beispiel für eine Plattform, die stark an E / A gebunden ist. Ein Multithread-Webserver, der einen Thread pro Verbindung zuweist, lässt sich nicht gut skalieren, da jeder Thread aufgrund des erhöhten Umfangs der Kontextumschaltung und der Thread-Sperre für gemeinsam genutzte Ressourcen einen höheren Overhead verursacht. Während ein asynchroner Webserver einen einzelnen Adressraum verwenden würde.

Ebenso würde eine auf das Codieren von Videos spezialisierte Anwendung in einer Umgebung mit mehreren Threads viel besser funktionieren, da die damit verbundene umfangreiche Verarbeitung den Haupt-Thread sperren würde, bis die Arbeit abgeschlossen ist. Es gibt verschiedene Möglichkeiten, dies zu verringern, aber es ist viel einfacher, einen einzelnen Thread zum Verwalten einer Warteschlange, einen zweiten Thread zum Verwalten der Bereinigung und einen Pool von Threads zum Verwalten der umfangreichen Verarbeitung zu haben. Die Kommunikation zwischen Threads erfolgt nur, wenn Aufgaben zugewiesen / abgeschlossen wurden, sodass der Aufwand für das Sperren von Threads auf ein Minimum beschränkt bleibt.

Die beste Anwendung verwendet oft eine Kombination aus beiden. Eine Webanwendung kann beispielsweise nginx (dh async single-threaded) als Load-Balancer zum Verwalten des Stroms eingehender Anforderungen, einen ähnlichen async-Webserver (ex Node.js) zum Verarbeiten von http-Anforderungen und eine Reihe von Multithread-Servern verwenden Upload / Streaming / Codierung von Inhalten, etc ...

Im Laufe der Jahre gab es viele Religionskriege zwischen Multi-Thread-, Multi-Prozess- und Async-Modellen. Wie bei den meisten Dingen sollte die beste Antwort wirklich "es kommt darauf an" sein.

Es folgt der gleichen Denkweise, die die parallele Verwendung von GPU- und CPU-Architekturen rechtfertigt. Zwei spezialisierte Systeme, die zusammen ausgeführt werden, können eine viel größere Verbesserung aufweisen als ein einzelner monolithischer Ansatz.

Weder sind besser, weil beide ihren Nutzen haben. Verwenden Sie das beste Werkzeug für den Job.

Aktualisieren:

Ich habe den Verweis auf Apache entfernt und eine kleine Korrektur vorgenommen. Apache verwendet ein Multiprozessmodell, das für jede Anforderung einen Prozess anfordert, wodurch der Umfang der Kontextumschaltung auf Kernelebene erhöht wird. Da der Speicher nicht von mehreren Prozessen gemeinsam genutzt werden kann, entstehen für jede Anforderung zusätzliche Speicherkosten.

Multithreading umgeht die Anforderung von zusätzlichem Speicher, da ein gemeinsamer Speicher zwischen Threads erforderlich ist. Shared Memory beseitigt den zusätzlichen Speicheraufwand, verursacht jedoch immer noch den Nachteil eines erhöhten Kontextwechsels. Darüber hinaus sind - um sicherzustellen, dass keine Race-Bedingungen auftreten - Thread-Sperren (die den exklusiven Zugriff auf jeweils nur einen Thread gewährleisten) für alle Ressourcen erforderlich, die von mehreren Threads gemeinsam genutzt werden.

Es ist lustig, dass Sie sagen: "Programmierer scheinen Parallel- und Multithread-Programme im Allgemeinen zu lieben." Multithread-Programmierung wird allgemein von jedem gefürchtet, der in seiner Zeit eine beträchtliche Menge davon gemacht hat. Dead Locks (ein Fehler, der auftritt, wenn eine Ressource fälschlicherweise von zwei verschiedenen Quellen gesperrt wird, die beide blockieren) und Race-Bedingungen (bei denen das Programm aufgrund falscher Reihenfolge fälschlicherweise das falsche Ergebnis zufällig ausgibt) sind einige der am schwierigsten zu verfolgenden runter und reparieren.

Update2:

Im Gegensatz zu der pauschalen Aussage, dass IPC schneller ist als die Netzwerk- (dh Socket-) Kommunikation. Das ist nicht immer der Fall . Beachten Sie, dass dies Verallgemeinerungen sind und implementierungsspezifische Details einen großen Einfluss auf das Ergebnis haben können.

Evan Scholle
quelle
Warum sollte ein Programmierer mehrere Prozesse ausführen? Ich gehe davon aus, dass Sie bei mehr als einem Prozess auch eine Art prozessübergreifende Kommunikation benötigen, die einen erheblichen Mehraufwand verursachen kann. wann soll ich multi-process gehen Danke übrigens für deine Antwort, ein wirklich gutes Bild davon, wofür Async und Multithreading gut sind.
user1849534
1
Sie gehen davon aus, dass die Interprozesskommunikation den Gesamtaufwand erhöhen würde. Allerdings, wenn der Verarbeitungsstatus unveränderlich ist oder nur die Synchronisierung beim Start / Abschluss verarbeiten muss. Es kann weitaus effizienter sein, sich auf parallelere Aufgaben zu konzentrieren. Das Schauspielermuster ist ein gutes Beispiel, und wenn Sie nicht darüber gelesen haben, lohnt es sich wirklich, sich darüber zu informieren. akka.io
sylvanaar
1
@ user1849534 Mehrere Threads können über Shared Memory + Locking oder IPC miteinander kommunizieren . Das Sperren ist einfacher, aber schwieriger zu debuggen, wenn Sie einen Fehler machen (zB ein Schloss verpasst, Dead Lock). IPC ist am besten geeignet, wenn Sie viele Arbeitsthreads haben, da das Sperren nicht gut skaliert werden kann. In beiden Fällen ist es bei Verwendung eines Multithread-Ansatzes wichtig, die Kommunikation / Synchronisation zwischen Threads auf ein absolutes Minimum zu beschränken (dh den Overhead zu minimieren).
Evan Plaice
1
@ akka.io Du hast vollkommen recht. Unveränderlichkeit ist eine Möglichkeit, den Mehraufwand für das Sperren zu minimieren / zu eliminieren, aber Sie haben immer noch die Zeitkosten für die Kontextumschaltung. Wenn Sie die Antwort so erweitern möchten, dass sie Details darüber enthält, wie durch Unveränderlichkeit Probleme mit der Thread-Synchronisierung behoben werden können, wenden Sie sich an uns. Der Hauptpunkt, den ich veranschaulichen wollte, ist, dass es Fälle gibt, in denen asynchrone Kommunikation einen deutlichen Vorteil gegenüber Multithreading / Prozess und umgekehrt hat.
Evan Plaice
(Forts.) Aber ehrlich gesagt, wenn ich viel CPU-gebundene Verarbeitungskapazität benötige, überspringe ich das Akteurmodell und baue es so auf, dass es auf mehrere Netzwerkknoten skaliert werden kann. Die beste Lösung, die ich dafür gesehen habe, ist die Verwendung des Task-Ventilator-Modells von 0MQ für die Kommunikation auf Socket-Ebene. Siehe Abb. 5 @ zguide.zeromq.org/page:all .
Evan Plaice
13

Der asynchrone Ansatz von Microsoft ist ein guter Ersatz für die häufigsten Zwecke der Multithread-Programmierung: Verbesserung der Reaktionsfähigkeit bei E / A-Aufgaben.

Es ist jedoch wichtig zu wissen, dass der asynchrone Ansatz nicht in der Lage ist, die Leistung oder die Reaktionsfähigkeit bei CPU-intensiven Aufgaben zu verbessern.

Multithreading für Reaktionsfähigkeit

Multithreading für die Reaktionsfähigkeit ist die traditionelle Methode, um ein Programm während schwerer E / A-Aufgaben oder schwerer Rechenaufgaben reaktionsfähig zu halten. Sie speichern Dateien in einem Hintergrund-Thread, damit der Benutzer seine Arbeit fortsetzen kann, ohne warten zu müssen, bis die Festplatte ihre Aufgabe abgeschlossen hat. Der E / A-Thread blockiert häufig das Warten, bis ein Teil des Schreibvorgangs abgeschlossen ist, sodass Kontextwechsel häufig vorkommen.

In ähnlicher Weise möchten Sie bei einer komplexen Berechnung eine regelmäßige Kontextumschaltung zulassen, damit die Benutzeroberfläche weiterhin reagiert und der Benutzer denkt, dass das Programm nicht abgestürzt ist.

Das Ziel ist hier im Allgemeinen nicht, dass die mehreren Threads auf verschiedenen CPUs ausgeführt werden. Stattdessen sind wir nur daran interessiert, Kontextwechsel zwischen der lang laufenden Hintergrundaufgabe und der Benutzeroberfläche zu veranlassen, damit die Benutzeroberfläche aktualisiert werden und dem Benutzer antworten kann, während die Hintergrundaufgabe ausgeführt wird. Im Allgemeinen nimmt die Benutzeroberfläche nicht viel CPU-Leistung in Anspruch, und das Threading-Framework oder das Betriebssystem entscheiden sich normalerweise dafür, sie auf derselben CPU auszuführen.

Wir verlieren tatsächlich die Gesamtleistung aufgrund der zusätzlichen Kosten für die Kontextumschaltung, aber das ist uns egal, da die Leistung der CPU nicht unser Ziel war. Wir wissen, dass wir in der Regel mehr CPU-Leistung haben, als wir benötigen, und daher besteht unser Ziel beim Multithreading darin, eine Aufgabe für den Benutzer zu erledigen, ohne die Zeit des Benutzers zu verschwenden.

Die "asynchrone" Alternative

Der "asynchrone Ansatz" ändert dieses Bild, indem Kontextwechsel innerhalb eines einzelnen Threads aktiviert werden. Dies stellt sicher, dass alle unsere Aufgaben auf einer einzelnen CPU ausgeführt werden und bietet möglicherweise einige bescheidene Leistungsverbesserungen in Bezug auf weniger Erstellung / Bereinigung von Threads und weniger echte Kontextwechsel zwischen Threads.

Anstatt einen neuen Thread zu erstellen, um auf den Empfang einer Netzwerkressource zu warten (z. B. Herunterladen eines Bildes), wird eine asyncMethode verwendet, bei der awaitdas Bild verfügbar wird und in der Zwischenzeit der aufrufenden Methode nachgibt.

Der Hauptvorteil hierbei ist, dass Sie sich keine Gedanken über Threading-Probleme wie das Vermeiden von Deadlocks machen müssen, da Sie überhaupt keine Sperren und Synchronisierungen verwenden und der Programmierer weniger Zeit für das Einrichten des Hintergrundthreads und das Zurückkehren hat auf dem UI-Thread, wenn das Ergebnis zurückkommt, um die Benutzeroberfläche sicher zu aktualisieren.

Ich habe mich nicht zu sehr mit den technischen Details befasst, aber ich habe den Eindruck, dass das Verwalten des Downloads mit gelegentlicher geringer CPU-Aktivität nicht zu einer Aufgabe für einen separaten Thread wird, sondern eher zu einer Aufgabe in der Ereigniswarteschlange der Benutzeroberfläche Wenn der Download abgeschlossen ist, wird die asynchrone Methode aus dieser Ereigniswarteschlange fortgesetzt. Mit anderen Worten awaitbedeutet so etwas wie "Überprüfen Sie, ob das von mir benötigte Ergebnis verfügbar ist. Wenn nicht, versetzen Sie mich zurück in die Task-Warteschlange dieses Threads".

Beachten Sie, dass dieser Ansatz das Problem einer CPU-intensiven Aufgabe nicht lösen würde: Es sind keine Daten zu erwarten, sodass wir nicht die erforderlichen Kontextwechsel durchführen können, ohne einen tatsächlichen Hintergrund-Worker-Thread zu erstellen. Natürlich kann es immer noch praktisch sein, eine asynchrone Methode zu verwenden, um den Hintergrund-Thread zu starten und das Ergebnis in einem Programm zurückzugeben, das den asynchronen Ansatz verwendet.

Multithreading für Leistung

Da Sie über "Leistung" sprechen, möchte ich auch diskutieren, wie Multithreading für Leistungssteigerungen verwendet werden kann, was mit dem asynchronen Singlethread-Ansatz völlig unmöglich ist.

Wenn Sie tatsächlich in einer Situation sind, in der Sie auf einer einzelnen CPU nicht genügend CPU-Leistung haben und Multithreading für die Leistung verwenden möchten, ist dies häufig schwierig. Auf der anderen Seite ist eine CPU, die nicht ausreicht, häufig auch die einzige Lösung, die es Ihrem Programm ermöglicht, in einem angemessenen Zeitrahmen das zu tun, was Sie erreichen möchten, was die Arbeit lohnt.

Triviale Parallelität

Natürlich kann es manchmal einfach sein, durch Multithreading eine echte Beschleunigung zu erzielen.

Wenn Sie eine große Anzahl unabhängiger rechenintensiver Aufgaben haben (dh Aufgaben, deren Eingabe- und Ausgabedaten im Hinblick auf die Berechnungen, die zur Ermittlung des Ergebnisses durchgeführt werden müssen, sehr klein sind), können Sie häufig eine erhebliche Beschleunigung erzielen Erstellen eines Pools von Threads (entsprechend der Anzahl der verfügbaren CPUs dimensioniert) und Verteilen der Arbeit und Sammeln der Ergebnisse durch einen Master-Thread.

Praktisches Multithreading für mehr Leistung

Ich möchte mich nicht als zu vielfacher Experte ausgeben, aber ich habe den Eindruck, dass das derzeit praktischste Multithreading für die Leistung darin besteht, nach Stellen in einer Anwendung mit trivialer Parallelität zu suchen und mehrere Threads zu verwenden von den Vorteilen profitieren.

Wie bei jeder Optimierung ist es normalerweise besser, zu optimieren, nachdem Sie das Leistungsprofil Ihres Programms erstellt und die Hotspots identifiziert haben: Es ist einfach, ein Programm zu verlangsamen, indem Sie willkürlich entscheiden, dass dieser Teil in einem Thread und dieser Teil in einem anderen ohne ausgeführt werden soll Ermitteln Sie zunächst, ob beide Teile einen erheblichen Teil der CPU-Zeit in Anspruch nehmen.

Ein zusätzlicher Thread bedeutet mehr Einrichtungs- / Abbaukosten und entweder mehr Kontextwechsel oder mehr Kommunikationskosten zwischen CPUs. Wenn es nicht genug Arbeit leistet, um diese Kosten auszugleichen, wenn es sich um eine separate CPU handelt, und aus Gründen der Reaktionsfähigkeit kein separater Thread sein muss, wird es die Dinge ohne Nutzen verlangsamen.

Suchen Sie nach Aufgaben, die nur wenige Abhängigkeiten aufweisen und einen erheblichen Teil der Laufzeit Ihres Programms beanspruchen.

Wenn sie keine gegenseitigen Abhängigkeiten aufweisen, handelt es sich um eine triviale Parallelität. Sie können jede einfach mit einem Thread einrichten und von den Vorteilen profitieren.

Wenn Sie Aufgaben mit begrenzter gegenseitiger Abhängigkeit finden, die durch Sperren und Synchronisieren zum Austauschen von Informationen nicht wesentlich verlangsamt werden, kann Multithreading zu einer Beschleunigung führen, vorausgesetzt, Sie vermeiden die Gefahr eines Deadlocks aufgrund fehlerhafter Logik bei der Synchronisierung oder falsche Ergebnisse, da nicht synchronisiert wird, wenn dies erforderlich ist.

Alternativ suchen einige der gängigsten Anwendungen für Multithreading (in gewissem Sinne) nicht nach einer Beschleunigung eines vorgegebenen Algorithmus, sondern nach einem größeren Budget für den Algorithmus, den sie schreiben möchten: wenn Sie eine Game-Engine schreiben Wenn Ihre KI eine Entscheidung innerhalb Ihrer Bildrate treffen muss, können Sie Ihrer KI häufig ein größeres CPU-Zyklusbudget zuweisen, wenn Sie ihr eine eigene CPU zuweisen können.

Stellen Sie jedoch sicher, dass Sie die Threads profilieren und sicherstellen, dass sie genug Arbeit leisten, um die Kosten zu einem bestimmten Zeitpunkt auszugleichen.

Parallele Algorithmen

Es gibt auch viele Probleme, die durch die Verwendung mehrerer Prozessoren beschleunigt werden können, die jedoch zu monolithisch sind, um sie einfach zwischen CPUs aufzuteilen.

Parallele Algorithmen müssen sorgfältig auf ihre Big-O-Laufzeiten hin analysiert werden, da es für die Kommunikationskosten zwischen den CPUs sehr einfach ist, die Vorteile der Verwendung mehrerer CPUs zu eliminieren. Im Allgemeinen müssen sie weniger Kommunikation zwischen CPUs (in Big-O-Begriffen) verwenden, als sie Berechnungen für jede CPU verwenden.

Im Moment ist es immer noch ein Raum für akademische Forschung, zum Teil wegen der komplexen Analyse, zum Teil, weil triviale Parallelität weit verbreitet ist, zum Teil, weil wir noch nicht so viele CPU-Kerne auf unseren Computern haben, die Probleme haben, die kann nicht in einem vernünftigen Zeitrahmen auf einer CPU gelöst werden könnte mit allen unseren CPUs in einem vernünftigen Zeitrahmen gelöst werden.

Theodore Murdock
quelle
+1 für eine offensichtlich gut durchdachte Antwort. Ich würde jedoch Microsoft-Vorschlägen mit Vorsicht begegnen. Denken Sie daran, dass .NET eine Synchron-First-Plattform ist. Daher ist das Ökosystem darauf ausgerichtet, bessere Einrichtungen / Dokumentationen bereitzustellen, die den Aufbau synchroner Lösungen unterstützen. Das Gegenteil wäre für asynchrone Plattformen wie Node.js der Fall.
Evan Plaice
3

Die Anwendung reagiert nicht und ist nur langsam und unangenehm.

Und da ist dein Problem. Eine reaktionsfähige Benutzeroberfläche erstellt keine performante Anwendung. Oft das Gegenteil. Es wird eine Menge Zeit aufgewendet, um die Eingabe der Benutzeroberfläche zu überprüfen, anstatt die Worker-Threads ihre Arbeit erledigen zu lassen.

Soweit es sich nur um einen asynchronen Ansatz handelt, ist dies auch Multithreading, obwohl es in den meisten Umgebungen für diesen einen bestimmten Anwendungsfall optimiert wurde . In anderen Fällen erfolgt die Asynchronisierung über Coroutinen, die nicht immer gleichzeitig ausgeführt werden.

Ehrlich gesagt finde ich, dass asynchrone Vorgänge schwieriger zu beurteilen und in einer Weise zu verwenden sind, die tatsächlich Vorteile bietet (Leistung, Robustheit, Wartbarkeit), sogar im Vergleich zu manuelleren Ansätzen.

Telastyn
quelle
Warum ? zum beispiel was findest du so bananen in der boost signals2 bibliothek?
user1849534