Multithreading: Was bringt mehr Threads als Kerne?


141

Ich dachte, der Sinn eines Multi-Core-Computers ist, dass er mehrere Threads gleichzeitig ausführen kann. Wenn Sie in diesem Fall eine Quad-Core-Maschine haben, was bringt es, wenn mehr als 4 Threads gleichzeitig ausgeführt werden? Würden sie sich nicht einfach Zeit (CPU-Ressourcen) stehlen?


52
wir genießen diese Art von Fragen, die sie sehr grundlegend etwas in Frage stellen, die für granted..keep kommen .. genommen wird
Srinivas Reddy Thatiparthy

6
Wann haben Sie Firefox, MS Word, Winamp, Eclipse und einen Download-Manager (mehr als vier Programme / Prozesse) das letzte Mal gleichzeitig auf Ihrem Quad-Core-Computer ausgeführt? Außerdem kann eine einzelne Anwendung manchmal mehr als vier Threads erzeugen - wie wäre es damit?
Amarghosh

1
Stehlen ist nicht unbedingt schlecht. Möglicherweise haben Sie einen Thread mit einer höheren Priorität für wichtige Aufgaben, die Zeit stehlen müssen.
Kichik

1
@Amarghosh Ich denke, das war die Frage, warum eine einzelne Anwendung möglicherweise mehr Threads als Kerne erzeugen möchte, wenn dies keinen Leistungsvorteil zu bringen scheint. Und Ihr Beispiel mit mehr als vier Programmen ist hier nicht ganz relevant. Wie Sie richtig bemerkt haben, sind dies Prozesse. Die Multitasking-Funktion des Betriebssystems (Prozessmultiplexing) hat sehr wenig mit Threads innerhalb eines Prozesses zu tun.
Aleksandr Ivannikov

Antworten:


81

Die Antwort dreht sich um den Zweck von Threads, nämlich Parallelität: mehrere separate Ausführungszeilen gleichzeitig auszuführen. In einem "idealen" System würde ein Thread pro Kern ausgeführt: keine Unterbrechung. In Wirklichkeit ist dies nicht der Fall. Selbst wenn Sie vier Kerne und vier Arbeitsthreads haben, werden Ihr Prozess und seine Threads ständig für andere Prozesse und Threads ausgetauscht. Wenn Sie ein modernes Betriebssystem ausführen, hat jeder Prozess mindestens einen Thread und viele mehr. Alle diese Prozesse werden gleichzeitig ausgeführt. Wahrscheinlich laufen gerade mehrere hundert Threads auf Ihrem Computer. Sie werden nie eine Situation bekommen, in der ein Thread läuft, ohne dass ihm Zeit "gestohlen" wird. (Nun, Sie könnten, wenn es in Echtzeit läuft , wenn Sie ein Echtzeit-Betriebssystem verwenden oder sogar unter Windows,

Vor diesem Hintergrund lautet die Antwort: Ja, mehr als vier Threads auf einem echten Vierkerncomputer können dazu führen, dass sie sich gegenseitig Zeit stehlen, jedoch nur, wenn jeder einzelne Thread 100% CPU benötigt . Wenn ein Thread nicht zu 100% funktioniert (wie es ein UI-Thread möglicherweise nicht tut oder ein Thread eine kleine Menge Arbeit erledigt oder auf etwas anderes wartet), ist ein anderer Thread, der geplant wird, tatsächlich eine gute Situation.

Es ist tatsächlich komplizierter als das:

  • Was ist, wenn Sie fünf Arbeiten haben, die alle gleichzeitig erledigt werden müssen? Es ist sinnvoller, sie alle gleichzeitig auszuführen, als vier davon auszuführen und dann die fünfte später auszuführen.

  • Es ist selten, dass ein Thread wirklich 100% CPU benötigt. In dem Moment, in dem beispielsweise Festplatten- oder Netzwerk-E / A verwendet werden, kann es möglicherweise zu Wartezeiten kommen, die nichts Nützliches bewirken. Dies ist eine sehr häufige Situation.

  • Wenn Sie Arbeiten ausführen müssen, besteht ein gängiger Mechanismus darin, einen Threadpool zu verwenden. Es mag sinnvoll erscheinen, die gleiche Anzahl von Threads wie Kerne zu haben, aber der .Net-Threadpool verfügt über bis zu 250 Threads pro Prozessor . Ich bin nicht sicher, warum sie dies tun, aber meine Vermutung hängt mit der Größe der Aufgaben zusammen, die zum Ausführen auf den Threads gegeben werden.

Also: Zeit zu stehlen ist keine schlechte Sache (und auch nicht wirklich Diebstahl: So soll das System funktionieren.) Schreiben Sie Ihre Multithread-Programme basierend auf der Art der Arbeit, die die Threads ausführen, bei der es sich möglicherweise nicht um CPU handelt -gebunden. Ermitteln Sie anhand der Profilerstellung und Messung die Anzahl der benötigten Threads. Möglicherweise ist es sinnvoller, in Aufgaben oder Jobs zu denken, als in Threads: Schreiben Sie Arbeitsobjekte und geben Sie sie einem Pool, der ausgeführt werden soll. Machen Sie sich keine Sorgen, es sei denn, Ihr Programm ist wirklich leistungskritisch :)


16
+1 für "aber nur wenn jeder einzelne Thread 100% CPU benötigt". Das war die Annahme, von der ich nicht wusste, dass ich sie machte.
Nick Heiner

Eine wunderbare Antwort auf eine gute Frage. Danke dir!
Edgecase

53

Nur weil ein Thread existiert, heißt das nicht immer, dass er aktiv läuft. Bei vielen Thread-Anwendungen werden einige der Threads in den Ruhezustand versetzt, bis sie etwas tun müssen. Beispielsweise können Benutzereingaben dazu führen, dass Threads aufgeweckt, verarbeitet und wieder in den Ruhezustand versetzt werden.

Threads sind im Wesentlichen einzelne Aufgaben, die unabhängig voneinander ausgeführt werden können, ohne dass der Fortschritt einer anderen Aufgabe bekannt sein muss. Es ist durchaus möglich, mehr davon zu haben, als Sie gleichzeitig laufen können. Sie sind immer noch nützlich, auch wenn sie manchmal hintereinander in der Schlange stehen müssen.


11
Gut gesagt. Das Argument "Ein Thread pro CPU" gilt nur für CPU-gebundenen Code. Asynchrone Programmierung ist ein weiterer Grund für die Verwendung von Threads.
Joshua Davis

26

Der Punkt ist, dass Sie, obwohl Sie keine echte Beschleunigung erhalten, wenn die Threadanzahl die Kernanzahl überschreitet, Threads verwenden können, um logische Teile zu entwirren, die nicht voneinander abhängig sein müssen.

Selbst in einer mäßig komplexen Anwendung versucht die Verwendung eines einzelnen Threads, alles schnell zu erledigen, den "Fluss" Ihres Codes zu beeinträchtigen. Der einzelne Thread verbringt die meiste Zeit damit, dies abzufragen, dies zu überprüfen und Routinen bedingt nach Bedarf aufzurufen, und es wird schwierig, etwas anderes als einen Morast von Kleinigkeiten zu erkennen.

Vergleichen Sie dies mit dem Fall, in dem Sie Threads Aufgaben zuweisen können, sodass Sie anhand eines einzelnen Threads sehen können, was dieser Thread tut. Beispielsweise kann ein Thread das Warten auf Eingaben von einem Socket blockieren, den Stream in Nachrichten analysieren, Nachrichten filtern und, wenn eine gültige Nachricht eingeht, an einen anderen Arbeitsthread weiterleiten. Der Worker-Thread kann Eingaben aus einer Reihe anderer Quellen bearbeiten. Der Code für jedes dieser Elemente weist einen sauberen, zielgerichteten Ablauf auf, ohne explizit überprüfen zu müssen, ob nichts anderes zu tun ist.

Wenn Sie die Arbeit auf diese Weise partitionieren, kann sich Ihre Anwendung darauf verlassen, dass das Betriebssystem plant, was als Nächstes mit der CPU zu tun ist, sodass Sie nicht überall in Ihrer Anwendung explizite bedingte Überprüfungen durchführen müssen, was möglicherweise blockiert und was verarbeitet werden kann.


1
Dies ist ein interessanter Gedanke ... Ich hatte immer gehört, dass Multithreading einer App eine zusätzliche Komplexität darstellt, aber was Sie sagen, macht Sinn.
Nick Heiner

Multithreading einer App erhöht die Komplexität, wenn ihre Anliegen nicht ausreichend voneinander getrennt sind. Wenn es mit minimaler Überlappung von Bedenken (und damit gemeinsamem Status) entworfen wurde, ist es eine Nettoersparnis bei Komplexitätsproblemen.
NUR MEINE RICHTIGE MEINUNG

Es gibt Möglichkeiten, Single-Threaded-Anwendungen so zu strukturieren, dass der Kontrollfluss auf der Ebene, auf der Sie Programme schreiben, klarer wird. OTOH, wenn Sie Ihre Threads so strukturieren können, dass sie nur Nachrichten aneinander weiterleiten (anstatt über gemeinsam genutzte Ressourcen zu verfügen), ist es ziemlich einfach, herauszufinden, was los ist, und alles zum Laufen zu bringen.
Donal Fellows

1
Sollte jedoch darauf hinweisen, dass die Verwendung von Threads die Dinge nur bis zu einem bestimmten Punkt vereinfachen kann. Allzu oft wird versucht, zwei Threads dazu zu bringen, die Arbeit zu erledigen, die zu Recht von einem erledigt werden sollte, wobei die Komplexität in kürzester Zeit zurückkehrt. Die Symptome hierfür sind übermäßige Kommunikations- und Synchronisierungsbedürfnisse, um ein gewünschtes Ergebnis zu koordinieren.
JustJeff

15

Wenn ein Thread auf eine Ressource wartet (z. B. Laden eines Werts aus dem RAM in ein Register, Festplatten-E / A, Netzwerkzugriff, Starten eines neuen Prozesses, Abfragen einer Datenbank oder Warten auf Benutzereingaben), kann der Prozessor an einer arbeiten einen anderen Thread und kehren Sie zum ersten Thread zurück, sobald die Ressource verfügbar ist. Dies reduziert die Zeit, die die CPU im Leerlauf verbringt, da die CPU Millionen von Vorgängen ausführen kann, anstatt im Leerlauf zu sitzen.

Stellen Sie sich einen Thread vor, der Daten von einer Festplatte lesen muss. Im Jahr 2014 arbeitet ein typischer Prozessorkern mit 2,5 GHz und kann möglicherweise 4 Befehle pro Zyklus ausführen. Mit einer Zykluszeit von 0,4 ns kann der Prozessor 10 Befehle pro Nanosekunde ausführen. Bei typischen Suchzeiten für mechanische Festplatten von etwa 10 Millisekunden kann der Prozessor 100 Millionen Anweisungen in der Zeit ausführen, die zum Lesen eines Werts von der Festplatte benötigt wird. Bei Festplatten mit kleinem Cache (4 MB Puffer) und Hybridlaufwerken mit wenigen GB Speicher können erhebliche Leistungsverbesserungen auftreten, da die Datenlatenz für sequentielle Lesevorgänge oder Lesevorgänge aus dem Hybridabschnitt um mehrere Größenordnungen schneller sein kann.

Ein Prozessorkern kann zwischen Threads wechseln (die Kosten für das Anhalten und Fortsetzen eines Threads betragen etwa 100 Taktzyklen), während der erste Thread auf eine Eingabe mit hoher Latenz wartet (alles, was teurer ist als Register (1 Takt) und RAM (5 Nanosekunden)) Festplatten-E / A, Netzwerkzugriff (Latenz von 250 ms), Lesen von Daten von einer CD oder einem langsamen Bus oder ein Datenbankaufruf. Wenn mehr Threads als Kerne vorhanden sind, kann nützliche Arbeit geleistet werden, während Aufgaben mit hoher Latenz gelöst werden.

Die CPU verfügt über einen Thread-Scheduler, der jedem Thread Priorität zuweist und es einem Thread ermöglicht, in den Ruhezustand zu wechseln und nach einer festgelegten Zeit fortzufahren. Es ist die Aufgabe des Thread-Schedulers, das Thrashing zu reduzieren, was auftreten würde, wenn jeder Thread nur 100 Anweisungen ausführen würde, bevor er wieder in den Ruhezustand versetzt wird. Der Overhead beim Wechseln von Threads würde den gesamten nützlichen Durchsatz des Prozessorkerns verringern.

Aus diesem Grund möchten Sie Ihr Problem möglicherweise in eine angemessene Anzahl von Threads aufteilen. Wenn Sie Code zur Durchführung der Matrixmultiplikation geschrieben haben, ist das Erstellen eines Threads pro Zelle in der Ausgabematrix möglicherweise übermäßig, während ein Thread pro Zeile oder pro n vorhanden ist Zeilen in der Ausgabematrix die Overhead-Kosten für das Erstellen, Anhalten und Fortsetzen von Threads verringern kann.

Dies ist auch der Grund, warum die Verzweigungsvorhersage wichtig ist. Wenn Sie eine if-Anweisung haben, die das Laden eines Werts aus dem RAM erfordert, der Hauptteil der if- und else-Anweisungen jedoch Werte verwendet, die bereits in Register geladen wurden, kann der Prozessor einen oder beide Zweige ausführen, bevor die Bedingung ausgewertet wurde. Sobald die Bedingung zurückkehrt, wendet der Prozessor das Ergebnis der entsprechenden Verzweigung an und verwirft die andere. Hier möglicherweise nutzlose Arbeiten auszuführen ist wahrscheinlich besser als zu einem anderen Thread zu wechseln, was zu Thrashing führen kann.

Auf dem Weg von Single-Core-Prozessoren mit hoher Taktrate zu Multi-Core-Prozessoren hat sich das Chip-Design darauf konzentriert, mehr Kerne pro Chip zu stopfen, die gemeinsame Nutzung von On-Chip-Ressourcen zwischen Kernen zu verbessern, Algorithmen für die Verzweigungsvorhersage zu verbessern und den Overhead für das Umschalten von Threads zu verbessern. und bessere Thread-Planung.


Das gleiche kann mit einem einzelnen Thread und einer Warteschlange gemacht werden: \ Gibt es wirklich einen Vorteil, wenn 80 Threads auf 2-4 Kernen vorhanden sind, gegenüber nur 2-4 Kernen, die Aufgaben aus einer Warteschlange auffressen, sobald sie eintreffen und sie haben nichts zu tun?
Dmitry

8

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.


6

Obwohl Sie Threads verwenden können, um Berechnungen abhängig von Ihrer Hardware zu beschleunigen, besteht eine ihrer Hauptanwendungen darin, aus Gründen der Benutzerfreundlichkeit mehr als eine Sache gleichzeitig zu tun.

Wenn Sie beispielsweise im Hintergrund etwas verarbeiten müssen und auch weiterhin auf Eingaben in die Benutzeroberfläche reagieren müssen, können Sie Threads verwenden. Ohne Threads würde die Benutzeroberfläche jedes Mal hängen bleiben, wenn Sie versuchen, eine schwere Verarbeitung durchzuführen.

Siehe auch diese verwandte Frage: Praktische Verwendung für Threads


Die Benutzeroberfläche ist ein klassisches Beispiel für eine E / A-gebundene Aufgabe. Es ist nicht gut, einen einzelnen CPU-Kern zu haben, der sowohl Verarbeitungs- als auch E / A-Aufgaben ausführt.
Donal Fellows

6

Ich bin mit der Behauptung von @ kyoryu, dass die ideale Anzahl ein Thread pro CPU ist, überhaupt nicht einverstanden.

Stellen Sie sich das so vor: Warum haben wir Multi-Processing-Betriebssysteme? Während des größten Teils der Computergeschichte hatten fast alle Computer eine CPU. Ab den 1960er Jahren verfügten alle "echten" Computer über Multi-Processing-Betriebssysteme (auch bekannt als Multi-Tasking).

Sie führen mehrere Programme aus, damit eines ausgeführt werden kann, während andere für Dinge wie E / A blockiert sind.

Lassen Sie uns Argumente beiseite legen, ob Windows-Versionen vor NT Multitasking waren. Seitdem hatte jedes echte Betriebssystem Multitasking. Einige setzen es nicht Benutzern aus, aber es ist trotzdem da, um beispielsweise das Radio des Mobiltelefons zu hören, mit dem GPS-Chip zu sprechen, Mauseingaben zu akzeptieren usw.

Threads sind nur Aufgaben, die etwas effizienter sind. Es gibt keinen grundlegenden Unterschied zwischen einer Aufgabe, einem Prozess und einem Thread.

Eine CPU ist eine schreckliche Sache, die man verschwenden muss. Halten Sie also viele Dinge bereit, um sie zu verwenden, wenn Sie können.

Ich werde zustimmen, dass mit den meisten prozeduralen Sprachen, C, C ++, Java usw., das Schreiben von richtigem thread-sicherem Code eine Menge Arbeit ist. Mit 6 Kern-CPUs auf dem heutigen Markt und 16 Kern-CPUs in der Nähe erwarte ich, dass sich die Leute von diesen alten Sprachen entfernen werden, da Multithreading immer wichtiger wird.

Meinungsverschiedenheiten mit @kyoryu sind nur IMHO, der Rest ist Tatsache.


5
Wenn Sie viele prozessorgebundene Threads haben, ist die ideale Anzahl eine pro CPU (oder vielleicht eine weniger, um eine zu lassen, um alle E / A und das Betriebssystem und all das Zeug zu verwalten). Wenn Sie IO-gebundene Threads haben, können Sie ziemlich viel auf einer einzelnen CPU stapeln. Verschiedene Apps haben unterschiedliche Mischungen aus prozessorgebundenen und E / A-gebundenen Aufgaben. Das ist völlig natürlich, aber warum muss man mit universellen Erklärungen vorsichtig sein?
Donal Fellows

1
Der wichtigste Unterschied zwischen Threads und Prozessen besteht natürlich darin, dass unter Windows kein fork () vorhanden ist. Daher ist die Erstellung von Prozessen sehr teuer, was zu einer übermäßigen Verwendung von Threads führt.
Ninjalj

Abgesehen von Proteinfaltung, SETI usw. gibt es keine praktischen Benutzeraufgaben, die sehr lange rechnergebunden sind. Es besteht immer die Notwendigkeit, Informationen vom Benutzer zu erhalten, mit der Festplatte zu sprechen, mit dem DBMS zu sprechen usw. Ja, die Kosten für fork () sind eines der vielen Dinge, die Cutler NT verfluchte, mit denen andere bei DEC wussten.
fishtoprecords

5

Stellen Sie sich einen Webserver vor, der eine beliebige Anzahl von Anforderungen bedienen muss. Sie müssen die Anforderungen parallel bearbeiten, da andernfalls jede neue Anforderung warten muss, bis alle anderen Anforderungen abgeschlossen sind (einschließlich des Sendens der Antwort über das Internet). In diesem Fall haben die meisten Webserver weit weniger Kerne als die Anzahl der Anforderungen, die sie normalerweise bedienen.

Dies erleichtert es auch dem Entwickler des Servers: Sie müssen nur ein Thread-Programm schreiben, das eine Anfrage bedient, Sie müssen nicht über das Speichern mehrerer Anfragen, die Reihenfolge, in der Sie sie bedienen, usw. nachdenken.


2
Sie schreiben Software für ein Betriebssystem, das Threading unterstützt, aber keine Kapazität zum Multiplexen von Io hat? Ich denke, der Webserver ist wahrscheinlich ein schlechtes Beispiel, da in diesem Fall das Multiplexen von io fast immer effizienter ist, als mehr Threads als Kerne zu erzeugen.
Jason Coco

3

Viele Threads schlafen und warten auf Benutzereingaben, E / A und andere Ereignisse.


Sicher. Verwenden Sie einfach den Task-Manager unter Windows oder TOP unter einem echten Betriebssystem und sehen Sie, wie viele Aufgaben / Prozesse gerade ausgeführt werden. Es ist immer 90% oder mehr.
fishtoprecords

2

Threads können die Reaktionsfähigkeit in UI-Anwendungen verbessern. Darüber hinaus können Sie Threads verwenden, um mehr Arbeit aus Ihren Kernen herauszuholen. Auf einem einzelnen Kern kann beispielsweise ein Thread E / A ausführen und ein anderer einige Berechnungen durchführen. Wenn es sich um einen Single-Thread handelt, könnte der Kern im Wesentlichen inaktiv sein und auf den Abschluss der E / A warten. Das ist ein ziemlich gutes Beispiel, aber Threads können definitiv verwendet werden, um Ihre CPU ein bisschen härter zu schlagen.


Insbesondere kann ein Thread auf E / A warten, während ein anderer die Berechnung durchführt. Wenn E / A (signifikante) CPU-Zyklen benötigt, hat die Ausführung in einem separaten Thread keinen Vorteil. Der Vorteil ist, dass Ihr Berechnungsthread ausgeführt werden kann, während Ihr E / A-Thread mit den Daumen dreht und darauf wartet, dass sich ein großer Aluminiumzylinder dreht oder Pakete über den Draht aus Island oder was auch immer ankommen.
Ken

2

Ein Prozessor oder eine CPU ist der physische Chip, der an das System angeschlossen ist. Ein Prozessor kann mehrere Kerne haben (ein Kern ist der Teil des Chips, der Anweisungen ausführen kann). Ein Kern kann dem Betriebssystem als mehrere virtuelle Prozessoren erscheinen, wenn er mehrere Threads gleichzeitig ausführen kann (ein Thread ist eine einzelne Folge von Anweisungen).

Ein Prozess ist ein anderer Name für eine Anwendung. Im Allgemeinen sind Prozesse unabhängig voneinander. Wenn ein Prozess stirbt, stirbt auch kein anderer Prozess. Es ist möglich, dass Prozesse kommunizieren oder Ressourcen wie Speicher oder E / A gemeinsam nutzen.

Jeder Prozess hat einen separaten Adressraum und Stapel. Ein Prozess kann mehrere Threads enthalten, die jeweils Anweisungen gleichzeitig ausführen können. Alle Threads in einem Prozess teilen sich den gleichen Adressraum, aber jeder Thread hat seinen eigenen Stapel.

Hoffentlich helfen Ihnen diese Definitionen und weitere Untersuchungen unter Verwendung dieser Grundlagen beim Verständnis.


2
Ich verstehe nicht, wie dies seine Frage überhaupt anspricht. Meine Interpretation seiner Frage bezieht sich auf die Thread-Nutzung von Kernen und die optimale Nutzung der verfügbaren Ressourcen oder auf das Verhalten von Threads, wenn Sie deren Anzahl erhöhen, oder auf etwas in dieser Richtung.
David

@ David vielleicht war es keine direkte Antwort auf meine Frage, aber ich habe immer noch das Gefühl, durch das Lesen gelernt zu haben.
Nick Heiner

1

Die ideale Verwendung von Threads ist in der Tat eine pro Kern.

Wenn Sie jedoch nicht ausschließlich asynchrone / nicht blockierende E / A verwenden, besteht eine gute Chance, dass irgendwann Threads auf E / A blockiert werden, die Ihre CPU nicht verwenden.

Außerdem erschweren typische Programmiersprachen die Verwendung von 1 Thread pro CPU. Sprachen, die auf Parallelität ausgelegt sind (z. B. Erlang), können es einfacher machen, keine zusätzlichen Threads zu verwenden.


Die Verwendung von Threads für regelmäßige Aufgaben ist ein sehr häufiger und willkommener Workflow, und es wäre viel weniger als ideal, wenn sie einen Kern stehlen würden.
Nick Bastin

@ Nick Bastin: Ja, aber es ist effizienter, diese Aufgaben in eine Aufgabenwarteschlange zu stecken und sie aus dieser Warteschlange (oder einer ähnlichen Strategie) auszuführen. Für eine optimale Effizienz schlägt 1 Thread pro Kern alle, da kein unnötiger Kontextwechsel und keine zusätzlichen Stapel zugewiesen werden müssen. Unabhängig davon muss die periodische Aufgabe einen Kern stehlen, während sie "aktiv" ist, da die CPU tatsächlich nur eine Aufgabe pro Kern ausführen kann (plus Dinge wie Hyperthreading, falls verfügbar).
Kyoryu

@ Nick Bastin: Leider eignen sich die meisten modernen Sprachen, wie ich in der Hauptantwort sagte, nicht gut für die einfache Implementierung eines Systems, das dies effektiv tut. Dies ist nicht trivial. Am Ende kämpfen Sie ein wenig gegen den typischen Sprachgebrauch.
Kyoryu

Mein Punkt ist nicht, dass ein Thread pro Kern nicht optimal ist, sondern dass ein Thread pro Kern ein Wunschtraum ist (es sei denn, Sie sind eingebettet), und es ist Zeitverschwendung, zu versuchen, ihn zu treffen Tun Sie, was es Ihnen einfach macht (und auf einem modernen Scheduler sowieso nicht weniger effizient ist), anstatt zu versuchen, die Anzahl der von Ihnen verwendeten Threads zu optimieren. Sollten wir ohne guten Grund Fäden spinnen? Natürlich nicht, aber ob Sie unnötig Computerressourcen verschwenden, ist unabhängig vom Threading ein Problem.
Nick Bastin

@ Nick Bastin: Zusammenfassend ist also ein Thread pro Kern ideal, aber tatsächlich ist es nicht sehr wahrscheinlich, dass dies erreicht wird. Ich hätte wahrscheinlich stärker als "etwas schwierig" sein sollen, wenn ich darüber gesprochen hätte, wie wahrscheinlich es ist, so etwas tatsächlich zu erreichen.
Kyoryu

1

Bei der Art und Weise, wie einige APIs entworfen wurden, haben Sie keine andere Wahl , als sie in einem separaten Thread auszuführen (alles mit Blockierungsvorgängen). Ein Beispiel wären die HTTP-Bibliotheken (AFAIK) von Python.

Normalerweise ist dies jedoch kein großes Problem (wenn es sich um ein Problem handelt, sollte das Betriebssystem oder die API mit einem alternativen asynchronen Betriebsmodus ausgeliefert werden, z. B. :) select(2), da dies wahrscheinlich bedeutet, dass der Thread während des Wartens auf E / A in den Ruhezustand versetzt wird O Abschluss. Auf der anderen Seite, wenn etwas eine schwere Berechnung tut, Sie haben , um es in einem separaten Thread als sagen sie gesagt, der GUI - Thread (es sei denn , Sie genießen manuelles Multiplexing).


1

Ich weiß, dass dies eine super alte Frage mit vielen guten Antworten ist, aber ich bin hier, um auf etwas hinzuweisen, das in der gegenwärtigen Umgebung wichtig ist:

Wenn Sie eine Anwendung für Multithreading entwerfen möchten, sollten Sie nicht für eine bestimmte Hardwareeinstellung entwerfen. Die CPU-Technologie schreitet seit Jahren recht schnell voran und die Anzahl der Kerne nimmt stetig zu. Wenn Sie Ihre Anwendung absichtlich so gestalten, dass nur 4 Threads verwendet werden, beschränken Sie sich möglicherweise (z. B.) auf ein Octa-Core-System. Jetzt sind sogar 20-Kern-Systeme im Handel erhältlich, sodass ein solches Design definitiv mehr schadet als nützt.


0

Als Antwort auf Ihre erste Vermutung: Multi-Core-Maschinen können gleichzeitig mehrere Prozesse ausführen, nicht nur die mehreren Threads eines einzelnen Prozesses.

Antwort auf Ihre erste Frage: Bei mehreren Threads geht es normalerweise darum, mehrere Aufgaben gleichzeitig in einer Anwendung auszuführen. Die klassischen Beispiele im Internet sind ein E-Mail-Programm, das E-Mails sendet und empfängt, und ein Webserver, der Seitenanforderungen empfängt und sendet. (Beachten Sie, dass es im Wesentlichen unmöglich ist, ein System wie Windows auf die Ausführung nur eines Threads oder sogar nur eines Prozesses zu reduzieren. Wenn Sie den Windows Task-Manager ausführen, wird normalerweise eine lange Liste aktiver Prozesse angezeigt, von denen viele mehrere Threads ausführen. )

Antwort auf Ihre zweite Frage: Die meisten Prozesse / Threads sind nicht CPU-gebunden (dh sie werden nicht kontinuierlich und ununterbrochen ausgeführt), sondern halten an und warten häufig, bis die E / A abgeschlossen ist. Während dieser Wartezeit können andere Prozesse / Threads ausgeführt werden, ohne den wartenden Code zu "stehlen" (selbst auf einem Single-Core-Computer).


-5

Ein Thread ist eine Abstraktion, mit der Sie Code schreiben können, der so einfach wie eine Abfolge von Operationen ist, ohne zu wissen, dass der Code mit anderen Codes verschachtelt ausgeführt wird oder auf E / A geparkt oder (möglicherweise etwas bewusster) auf andere Threads gewartet wird Ereignisse oder Nachrichten.


Ich hätte dies möglicherweise bearbeiten können, indem ich seit den Abstimmungen weitere Beispiele hinzugefügt habe - aber ein Thread (oder Prozess, in diesem Zusammenhang fast kein Unterschied) wurde nicht erfunden, um die Leistung zu steigern, sondern um asynchronen Code zu vereinfachen und das Schreiben komplizierter Zustandsmaschinen zu vermeiden das musste mit allen im Programm möglichen Superzuständen umgehen. Tatsächlich gab es selbst bei großen Servern normalerweise eine CPU. Ich bin nur neugierig, warum meine Antwort als nicht hilfreich angesehen wird.
KarlP

-8

Der Punkt ist, dass die überwiegende Mehrheit der Programmierer nicht versteht, wie man eine Zustandsmaschine entwirft. Wenn der Programmierer in der Lage ist, alles in einen eigenen Thread zu stellen, muss er nicht mehr darüber nachdenken, wie er den Status verschiedener laufender Berechnungen effizient darstellen kann, damit sie unterbrochen und später wieder aufgenommen werden können.

Betrachten Sie als Beispiel die Videokomprimierung, eine sehr CPU-intensive Aufgabe. Wenn Sie ein GUI-Tool verwenden, möchten Sie wahrscheinlich, dass die Benutzeroberfläche weiterhin reagiert (Fortschritt anzeigen, auf Abbruchanforderungen reagieren, Fenstergröße ändern usw.). Sie entwerfen Ihre Encoder-Software so, dass eine große Einheit (ein oder mehrere Frames) gleichzeitig verarbeitet und in einem eigenen Thread ausgeführt wird, der von der Benutzeroberfläche getrennt ist.

Sobald Sie feststellen, dass es schön gewesen wäre, den laufenden Codierungsstatus zu speichern, damit Sie das Programm schließen können, um einen Neustart durchzuführen oder ein ressourcenhungriges Spiel zu spielen, sollten Sie natürlich gelernt haben, wie man Zustandsautomaten aus dem Anfang. Entweder das, oder Sie entscheiden sich für ein völlig neues Problem des Ruhezustands Ihres Betriebssystems, damit Sie einzelne Apps anhalten und auf der Festplatte wieder aufnehmen können ...


7
Nicht (ganz!) Eine -1 wert, aber im Ernst, das ist ungefähr das Dümmste, was ich je von jemandem zu diesem Thema gehört habe. Ich habe zum Beispiel keine Probleme bei der Implementierung einer Zustandsmaschine. Überhaupt keine. Ich mag es einfach nicht, sie zu verwenden, wenn andere Tools vorhanden sind, die klareren und einfacher zu pflegenden Code hinterlassen . Zustandsautomaten haben ihre Plätze, und an diesen Orten können sie nicht verglichen werden. Das Interlacing von CPU-intensiven Vorgängen mit GUI-Updates gehört nicht dazu. Zumindest sind Coroutinen dort eine bessere Wahl, wobei das Einfädeln noch besser ist.
Nur meine richtige Meinung

Für alle, die meine Antwort nach unten ändern, ist dies KEIN Argument gegen die Verwendung von Threads! Wenn Sie eine Zustandsmaschine codieren können, ist das großartig, und sicher ist es oft sinnvoll, Zustandsmaschinen in separaten Threads auszuführen, auch wenn Sie dies nicht müssen. Mein Kommentar war, dass die Entscheidung für die Verwendung von Threads häufig in erster Linie aus dem Wunsch heraus getroffen wird, das Entwerfen von Zustandsmaschinen zu vermeiden, die viele Programmierer als "zu schwer" betrachten, und nicht für andere Vorteile.
R .. GitHub STOP HELPING ICE
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.