Um eine Geschwindigkeitsverbesserung aufgrund einer Form von Multi-Computing zu vermuten, müssen Sie entweder davon ausgehen, dass mehrere CPU-basierte Aufgaben gleichzeitig auf mehreren Computerressourcen (im Allgemeinen Prozessorkerne) ausgeführt werden oder dass nicht alle Aufgaben auf der gleichzeitigen Verwendung von basieren Dieselbe Ressource - das heißt, einige Aufgaben hängen möglicherweise von einer Systemunterkomponente ab (z. B. Festplattenspeicher), während einige Aufgaben von einer anderen abhängen (Empfang von Kommunikation von einem Peripheriegerät), und andere erfordern möglicherweise die Verwendung von Prozessorkernen.
Das erste Szenario wird oft als "parallele" Programmierung bezeichnet. Das zweite Szenario wird häufig als "gleichzeitige" oder "asynchrone" Programmierung bezeichnet, obwohl "gleichzeitig" manchmal auch verwendet wird, um den Fall zu bezeichnen, dass ein Betriebssystem lediglich die Ausführung mehrerer Aufgaben verschachteln kann, unabhängig davon, ob eine solche Ausführung erforderlich ist seriell platzieren oder wenn mehrere Ressourcen verwendet werden können, um eine parallele Ausführung zu erreichen. In diesem letzteren Fall bezieht sich "gleichzeitig" im Allgemeinen auf die Art und Weise, wie die Ausführung in das Programm geschrieben wird, und nicht auf die Perspektive der tatsächlichen Gleichzeitigkeit der Aufgabenausführung.
Es ist sehr einfach, mit stillschweigenden Annahmen darüber zu sprechen. Einige behaupten beispielsweise schnell: "Asynchrone E / A sind schneller als Multithread-E / A." Diese Behauptung ist aus mehreren Gründen zweifelhaft. Erstens könnte es vorkommen, dass einige gegebene asynchrone E / A-Frameworks genau mit Multithreading implementiert werden. In diesem Fall sind sie ein und dasselbe und es macht keinen Sinn zu sagen, dass ein Konzept "schneller als" das andere ist .
Zweitens müssen Sie auch dann, wenn eine Single-Threaded-Implementierung eines asynchronen Frameworks (z. B. einer Single-Threaded-Ereignisschleife) vorhanden ist, eine Annahme darüber treffen, was diese Schleife tut. Eine dumme Sache, die Sie mit einer Single-Threaded-Ereignisschleife tun können, ist beispielsweise die Anforderung, zwei verschiedene rein CPU-gebundene Aufgaben asynchron auszuführen. Wenn Sie dies auf einem Computer mit nur einem idealisierten Einzelprozessorkern tun würden (ohne Berücksichtigung moderner Hardwareoptimierungen), würde die Ausführung dieser Aufgabe "asynchron" nicht anders ablaufen als mit zwei unabhängig verwalteten Threads oder mit nur einem einzigen Prozess. - Der Unterschied kann auf das Umschalten des Thread-Kontexts oder die Optimierung des Betriebssystemplans zurückzuführen sein. Wenn jedoch beide Aufgaben an die CPU gehen, ist dies in beiden Fällen ähnlich.
Es ist nützlich, sich viele der ungewöhnlichen oder dummen Eckfälle vorzustellen, auf die Sie stoßen könnten.
"Asynchron" muss nicht gleichzeitig sein, zum Beispiel wie oben: Sie "asynchron" führen zwei CPU-gebundene Tasks auf einem Computer mit genau einem Prozessorkern aus.
Die Ausführung mit mehreren Threads muss nicht gleichzeitig erfolgen: Sie erzeugen zwei Threads auf einem Computer mit einem einzelnen Prozessorkern oder fordern zwei Threads auf, eine andere Art von knapper Ressource zu erwerben (stellen Sie sich beispielsweise eine Netzwerkdatenbank vor, die nur einen einrichten kann Verbindung zu einem Zeitpunkt). Die Ausführung der Threads kann verschachtelt sein, wie es der Scheduler des Betriebssystems für richtig hält, aber ihre Gesamtlaufzeit kann nicht auf einem einzelnen Kern reduziert werden (und wird durch das Wechseln des Thread-Kontexts erhöht) (oder allgemeiner, wenn Sie mehr Threads erzeugen als vorhanden Kerne, um sie auszuführen, oder mehr Threads, die nach einer Ressource fragen, als die Ressource aushalten kann). Das Gleiche gilt auch für die Mehrfachverarbeitung.
Daher müssen weder asynchrone E / A noch Multithreading einen Leistungsgewinn in Bezug auf die Laufzeit bieten. Sie können sogar die Dinge verlangsamen.
Wenn Sie jedoch einen bestimmten Anwendungsfall definieren, z. B. ein bestimmtes Programm, das sowohl einen Netzwerkaufruf zum Abrufen von Daten von einer mit dem Netzwerk verbundenen Ressource wie einer entfernten Datenbank ausführt als auch eine lokale CPU-gebundene Berechnung durchführt, können Sie anfangen, darüber nachzudenken Die Leistungsunterschiede zwischen den beiden Methoden unter einer bestimmten Annahme über die Hardware.
Die zu stellenden Fragen: Wie viele Rechenschritte muss ich ausführen und wie viele unabhängige Ressourcensysteme gibt es, um sie auszuführen? Gibt es Teilmengen der Rechenschritte, die die Verwendung unabhängiger Systemunterkomponenten erfordern und davon gleichzeitig profitieren können? Wie viele Prozessorkerne habe ich und wie hoch ist der Aufwand für die Verwendung mehrerer Prozessoren oder Threads, um Aufgaben auf separaten Kernen auszuführen?
Wenn Ihre Aufgaben weitgehend von unabhängigen Subsystemen abhängen, ist eine asynchrone Lösung möglicherweise hilfreich. Wenn die Anzahl der für die Verarbeitung erforderlichen Threads groß wäre, sodass die Kontextumschaltung für das Betriebssystem nicht mehr trivial wäre, ist eine asynchrone Lösung mit einem Thread möglicherweise besser.
Immer wenn die Aufgaben an dieselbe Ressource gebunden sind (z. B. müssen mehrere gleichzeitig auf dasselbe Netzwerk oder dieselbe lokale Ressource zugreifen), führt Multithreading wahrscheinlich zu einem unbefriedigenden Overhead, und während Single-Threaded-Asynchronität in einer solchen Ressource möglicherweise weniger Overhead verursacht. begrenzte Situation kann es auch keine Beschleunigung erzeugen. In einem solchen Fall besteht die einzige Option (wenn Sie eine Beschleunigung wünschen) darin, mehrere Kopien dieser Ressource verfügbar zu machen (z. B. mehrere Prozessorkerne, wenn die knappe Ressource CPU ist; eine bessere Datenbank, die mehr gleichzeitige Verbindungen unterstützt, wenn die knappe Ressource vorhanden ist ist eine verbindungsbeschränkte Datenbank usw.).
Eine andere Möglichkeit ist: Das Betriebssystem kann die Verwendung einer einzelnen Ressource für zwei Aufgaben verschachteln. Dies kann nicht schneller sein, als nur eine Aufgabe die Ressource verwenden zu lassen, während die andere wartet, und dann die zweite Aufgabe seriell zu beenden. Darüber hinaus bedeuten die Scheduler-Kosten für das Interleaving, dass in jeder realen Situation tatsächlich eine Verlangsamung auftritt. Es spielt keine Rolle, ob die verschachtelte Nutzung der CPU, einer Netzwerkressource, einer Speicherressource, eines Peripheriegeräts oder einer anderen Systemressource erfolgt.