Die meisten der obigen Antworten beziehen sich auf Leistung und gleichzeitigen Betrieb. Ich werde dies aus einem anderen Blickwinkel betrachten.
Nehmen wir zum Beispiel ein vereinfachtes Terminalemulationsprogramm. Sie müssen folgende Dinge tun:
- Achten Sie auf eingehende Zeichen vom Remote-System und zeigen Sie sie an
- Achten Sie auf Daten, die von der Tastatur kommen, und senden Sie sie an das Remote-System
(Echte Terminalemulatoren leisten mehr, einschließlich des potenziellen Echo der von Ihnen eingegebenen Daten auf dem Display, aber wir werden dies vorerst weitergeben.)
Jetzt ist die Schleife zum Lesen von der Fernbedienung gemäß dem folgenden Pseudocode einfach:
while get-character-from-remote:
print-to-screen character
Die Schleife zum Überwachen der Tastatur und zum Senden ist ebenfalls einfach:
while get-character-from-keyboard:
send-to-remote character
Das Problem ist jedoch, dass Sie dies gleichzeitig tun müssen. Der Code muss jetzt mehr so aussehen, wenn Sie kein Threading haben:
loop:
check-for-remote-character
if remote-character-is-ready:
print-to-screen character
check-for-keyboard-entry
if keyboard-is-ready:
send-to-remote character
Die Logik ist selbst in diesem bewusst vereinfachten Beispiel, das die reale Komplexität der Kommunikation nicht berücksichtigt, ziemlich verschleiert. Beim Threading können die beiden Pseudocode-Schleifen jedoch auch auf einem einzelnen Kern unabhängig voneinander existieren, ohne ihre Logik zu verschachteln. Da beide Threads größtenteils E / A-gebunden sind, wird die CPU nicht stark belastet, obwohl sie streng genommen mehr CPU-Ressourcen verschwenden als die integrierte Schleife.
Jetzt ist die Verwendung in der realen Welt natürlich komplizierter als oben beschrieben. Die Komplexität der integrierten Schleife steigt jedoch exponentiell an, wenn Sie der Anwendung weitere Bedenken hinzufügen. Die Logik wird immer fragmentierter und Sie müssen Techniken wie Zustandsautomaten, Coroutinen usw. verwenden, um die Dinge handhabbar zu machen. Überschaubar, aber nicht lesbar. Durch Threading bleibt der Code besser lesbar.
Warum sollten Sie kein Threading verwenden?
Wenn Ihre Aufgaben CPU-gebunden statt E / A-gebunden sind, verlangsamt Threading Ihr System tatsächlich. Die Leistung wird leiden. In vielen Fällen viel. ("Thrashing" ist ein häufiges Problem, wenn Sie zu viele CPU-gebundene Threads löschen. Sie verbringen mehr Zeit damit, die aktiven Threads zu ändern, als den Inhalt der Threads selbst auszuführen.) Einer der Gründe ist die obige Logik So einfach ist, dass ich ganz bewusst ein vereinfachtes (und unrealistisches) Beispiel gewählt habe. Wenn Sie die Eingabe auf dem Bildschirm wiederholen möchten, haben Sie eine neue Welt voller Verletzungen, wenn Sie die Sperrung gemeinsam genutzter Ressourcen einführen. Mit nur einer gemeinsam genutzten Ressource ist dies nicht so sehr ein Problem, aber es wird immer größer, je mehr Ressourcen Sie gemeinsam nutzen können.
Am Ende geht es beim Threading also um viele Dinge. Zum Beispiel geht es darum, E / A-gebundene Prozesse reaktionsfähiger zu machen (auch wenn sie insgesamt weniger effizient sind), wie einige bereits gesagt haben. Es geht auch darum, die Logik einfacher zu befolgen (aber nur, wenn Sie den gemeinsamen Status minimieren). Es geht um eine Menge Dinge, und Sie müssen von Fall zu Fall entscheiden, ob die Vorteile die Nachteile überwiegen.