Der Task-Manager gibt an, dass das System mit über tausend Threads ausgeführt wird

17

Ich öffnete den Task-Manager und schaute unter "System" und sah:

Themen: 1337

Da ich einen Dual-Core-Prozessor mit Hyper-Threading (dh vier Threads) habe, wie ist es möglich, über 1000 Threads zu haben, wenn mein Prozessor nur vier haben soll?

dpl47
quelle
3
Nennen sie es nicht Hyper- Threading? :)
ein CVn
9
Gee, haben sie endlich "Multiprogramming" erfunden ??? (Dies ist 1967, richtig?)
Daniel R Hicks
10
Hat gerade jemand die Nummer auf 1337 geändert?
Erty Seidohl
11
Wie kann ein Unternehmen mit vier Schreibtischen 1337 Mitarbeiter haben? Einfach; Die Mitarbeiter wechseln sich an den Schreibtischen ab.
Eric Lippert

Antworten:

50

Die einfache Antwort lautet, dass nicht alle Threads gleichzeitig ausgeführt werden. Für eine ausführlichere Erklärung lesen Sie bitte weiter.

Der Task-Scheduler des Betriebssystems dient im Allgemeinen zum Planen von Anwendungen. Auf diese Weise können Sie eine Aufgabe ausführen, während der Computer an einer anderen arbeitet. In früheren Zeiten bestand der Lackmustest für Multitasking darin, eine Diskette zu formatieren und dabei etwas anderes zu tun. Wenn Sie das Betriebssystem wirklich testen möchten, müssen Sie eine Diskette formatieren, während Sie eine Datei über ein Modem herunterladen, das an die serielle Schnittstelle angeschlossen ist. Da die Hardware leistungsfähig genug wurde, um dies tatsächlich auf sinnvolle Weise zu tun, wurde in solchen Tests manchmal auch die Videowiedergabe durchgeführt. Wenn der Task Scheduler des Betriebssystems diese Aufgaben reibungslos ausführen könnte, könnte er alles erledigen.

Der Taskplaner plant jedoch keine Anwendungen (Prozesse), sondern Threads . Jede Anwendung verfügt über mindestens einen Thread, kann jedoch möglicherweise eine große Anzahl von Threads verwenden, um die von ihr ausgeführte Arbeit in verwandte oder unabhängige Teile aufzuteilen. In einer Anwendung ist es beispielsweise üblich, einen Thread zu haben, der die Benutzeroberfläche verwaltet, und einen anderen Thread zu erstellen, wenn der Benutzer einen möglicherweise lang andauernden Vorgang einleitet (z. B. Drucken, Neuberechnen einer Tabelle, Ausführen einer Entwicklungsumgebung) eine Symbolsuche usw. usw.). Einige Programmierumgebungen führen einige Threads ein, die für den Programmierer unsichtbar sind. zum Beispiel Java und .NET tun könnten Garbage Collectionin einem separaten Thread, der sich der unmittelbaren Kontrolle des Programmierers entzieht. Einige Programme erstellen frühzeitig eine Reihe von Threads und bündeln sie, da das Erstellen neuer Threads eine vergleichsweise teure Operation ist (Sie müssen also nicht unbedingt jedes Mal einen Thread erstellen, wenn Sie einen benötigen). Alles, was eine Vorschau ausführt, wird normalerweise in einem separaten Thread ausgeführt, sodass der Rest der Benutzeroberfläche während der Erstellung der Vorschau weiterhin reagiert. Und so weiter. Alles in allem bedeutet dies, dass die Anzahl der Threads im System jederzeit ein Vielfaches der Anzahl der Prozesse betragen kann.

Jeder Thread kann sich in einem von wenigen möglichen Status befinden, der wichtigste Unterschied besteht jedoch in den Status " Laufen" , " Laufen" und " Warten" . Die Terminologie kann leicht abweichen, aber das ist die allgemeine Idee. Zu jeder Zeit, nur ein Thread pro virtuellem (wegen der Hyper - Threading und ähnliche Technologien) CPU - Kern kann laufen (das heißt, Maschinencode Befehle ausführt), aber eine beliebige Anzahl von Threads können sein runnable (was bedeutet , dass es ein Kandidat zu bekommen die CPU, wenn der Scheduler das nächste Mal eine Entscheidung treffen muss, welcher Thread ausgeführt werden darf). Warten (auch als blockiert bezeichnet) Threads sind genau das, was auf etwas wartet - die häufigsten Fälle sind wahrscheinlich, dass sie auf Benutzer-, Festplatten- oder Netzwerk-E / A warten (insbesondere Benutzereingaben sind außergewöhnlich langsam).

Die im Task-Manager angezeigte Thread-Anzahl gibt die Gesamtzahl der Threads in einem dieser Status an. Auf dem Windows 7-System, auf dem ich dies schreibe, sind derzeit etwa 70 Prozesse gestartet, aber fast 900 Threads. Bei all den Hintergrundprozessen zur Bewältigung verschiedener Aufgaben und wie sie wahrscheinlich in eine Vielzahl von Threads unterteilt sind, ist dies keine unverschämte Zahl.

Der Task-Scheduler eines vorbeugenden Multitasking-Betriebssystems befasst sich in der Regel mit einer Art Hardware-Interrupt-Hook. Dies bedeutet, dass der Kernel die CPU anhalten kann, wenn er keine nützliche Arbeit zu erledigen hat (dies ist mit ziemlicher Sicherheit einer der Gründe, wenn nicht der Grund, warum Linux die HLTAnweisung beim Booten auf IA-32 überprüft-kompatible CPUs (und führt wahrscheinlich ähnliche Überprüfungen für andere Architekturen durch), in der Gewissheit, dass zu einem vernünftigen Zeitpunkt ein Interrupt ausgelöst und der Task-Scheduler aufgerufen wird. Da der Interrupt unabhängig von der von der CPU ausgeführten Arbeit ausgelöst wird (das ist die Idee, die hinter Interrupts steckt), wird der Scheduler regelmäßig ausgeführt und kann bestimmen, welcher Thread während der folgenden Zeitscheibe ausgeführt werden soll. Da Kontextwechsel relativ teuer sind, kann normalerweise (zumindest über den Quellcode) eingestellt werden, wie aggressiv der Scheduler zwischen Threads wechselt. Durch häufigeres Wechseln der Threads reagiert das System schneller, der Mehraufwand für das Wechseln bedeutet jedoch, dass die Gesamtzeit zum Beenden eines bestimmten Satzes von Tasks länger ist. Am schnellstenDas System wechselt nur dann zwischen Threads, wenn der laufende Thread nicht mehr ausgeführt werden kann (was bedeutet, dass er blockiert wird, wenn er auf etwas wartet oder seine Arbeit beendet hat), da dies den Overhead minimiert, während das am schnellsten reagierende System zwischen Threads wechselt Jedes Mal, wenn der Scheduler aufgerufen wird, wird die durchschnittliche Wartezeit minimiert, bevor ein bestimmter Thread CPU-Zeit erhält. Die ideale Einstellung liegt normalerweise irgendwo dazwischen, und der Kompromiss zwischen diesen Optionen ist wahrscheinlich ein wichtiger Grund, warum Linux mehrere Scheduler zur Auswahl sowie einige Optimierungsparameter über die Kernelkonfiguration anbietet.

Auf der anderen Seite verlassen sich kooperative Multitasking-Betriebssysteme und -Umgebungen ( Windows 3.x ist ein Beispiel) darauf, dass jede Anwendung die Kontrolle regelmäßig an den Scheduler übergibt. In der Regel gibt es eine API-Funktion, die speziell dafür vorgesehen ist, und oft tun dies viele API-Funktionen im Rahmen ihres internen Ausführungsflusses, da dies dazu beiträgt, die Benutzerfreundlichkeit zu verbessern. Dieser Entwurfsansatz funktioniert gut, solange sich alle Anwendungen gut verhalten und die Steuerung in kurzen Intervallen während lang andauernder Vorgänge (lang andauernd bedeutet mehr als einen kleinen Bruchteil einer Sekunde) abtreten, aber eine Anwendung, die nicht verstopfen kann das gesamte System. Dies ist ein wichtiger Grund, warum Windows 3.x beim oben erwähnten Multitasking-Test unter OS / 2 so schlecht abgeschnitten hatEnglisch: emagazine.credit-suisse.com/app/art...1007 & lang = en Eine Anwendung könnte das Diskettenlaufwerk anweisen, einen bestimmten Sektor zu schreiben, und die Zeit, die bis zur Rückgabe des Anrufs erforderlich war, könnte tatsächlich messbar sein (Dutzende bis Hunderte von Millisekunden oder Sekunden) Mehr); Bei einem präventiven Multitasking-System bricht der Scheduler beim nächsten geplanten Aufruf ein. Beachten Sie, dass der aktuell "laufende" Thread durch den Schreibaufruf blockiert wird, und wechseln Sie einfach zu einem anderen Thread, der ausgeführt werden kann. (In der Praxis ist es etwas komplizierter, aber das ist die allgemeine Idee.)

Sowohl in präventivem Multitasking als auch in kooperativen Umgebungen besteht die Möglichkeit, dass unterschiedliche Threads unterschiedliche Prioritäten haben. Beispielsweise ist es wahrscheinlich wichtiger, den Thread, der Daten über eine Kommunikationsverbindung empfängt, rechtzeitig auszuführen, als den Thread, der die Systemzeitanzeige aktualisiert, sodass der empfangende Thread eine hohe Priorität und der Updater-Thread für die Zeitanzeige eine niedrige Priorität hat . Thread-Prioritäten spielen eine Rolle bei der Entscheidung des Schedulers, welcher Thread ausgeführt werden soll (z. B. sehr vereinfacht)Threads mit hoher Priorität sollten immer vor Threads mit niedriger Priorität ausgeführt werden. Selbst wenn der Thread mit niedriger Priorität noch zu arbeiten hat, hat er Vorrang, wenn der Thread mit hoher Priorität ausführbar wird. Solche spezifischen Planungsentscheidungen haben jedoch keine Auswirkungen auf den zugrunde liegenden Mechanismusentwurf.

ein CVn
quelle
11
Ich liebe "Benutzereingaben sind besonders langsam"
John Dvorak
Die "Threads", die eine CPU "hat", beziehen sich auf die Nummer, die sie zu einem bestimmten Zeitpunkt gleichzeitig ausführen kann. Es wird zwischen aktiven Threads umgeschaltet, wobei nach Möglichkeit für einen bestimmten Zeitraum jeweils eine Umdrehung oder ein Teil der CPU ausgeführt wird. Prozesse / Threads, die "blockiert" sind oder auf E / A warten (z. B. Festplatten-, Tastatur- / Mauseingaben usw.), oder andere Vorgänge (z. B. Synchronisationsprimitive wie Mutexe usw.), überspringen ihren Zug.
LawrenceC
1
Kommentare sind nett, um Klarheit zu bitten, aber sie eignen sich nicht für längere Diskussionen und sind irgendwann schwer zu lesen. Können Sie dies stattdessen zum Super User Chat bringen ? Vielen Dank.
Slhck
1
@slhck Ich habe einen Raum erstellt, konnte aber in diesen Kommentaren keine Möglichkeit finden, die Diskussion zu migrieren. Das wäre schön. Können Sie das als Moderator manuell tun? chat.stackexchange.com/rooms/9547/…
ein CVn
1
Unglücklicherweise nicht. Es gibt einen automatischen Migrationsprozess, der nicht manuell ausgelöst werden kann, aber wir können keine Kommentare in einen Chatroom verschieben. Wir werden die Kommentare hier vorerst beibehalten, aber ich möchte andere dazu ermutigen, die Diskussion in dem von Ihnen erstellten Chatroom weiter zu verfolgen.
Slhck
18

Denken Sie an eine vierspurige Autobahn mit 1037 Fahrzeugen.

Ihr Betriebssystem benötigt viele laufende Prozesse, um für viele Dienste zu funktionieren. Selbst die einfachsten Grafikprogramme erfordern Multithread-Programmierung. Wenn Sie an viele geöffnete Programme denken, müssen Sie die Rechenleistung gemeinsam nutzen.

Was Ihr Task-Manager anzeigt, ist die aktuelle Systemlast. Ihre Kompositionsspezifikationen zeigen an, wie viele Threads (im Frontend) für die parallele Ausführung akzeptiert werden. Ohne viel in den Unterschied zwischen Hyperthreading- und Multicore-Funktionen einzugehen, wird ein System im Allgemeinen eine bessere Leistung erzielen, wenn mehr logische Frontend-Threads akzeptiert werden.

174140
quelle
8
"Selbst die einfachsten Grafikprogramme erfordern Multithread-Programmierung." Falsch. Es ist durchaus möglich, Singlethread-GUI-Anwendungen zu schreiben. Bis Windows 95 taten es in jeder Hinsicht alle so. Dadurch werden bestimmte Aufgaben komplizierter (z. B. ist das Drucken im Hintergrund bei mehreren Threads trivial, in einer Anwendung mit einem einzigen Thread jedoch entschieden nicht trivial, insbesondere, wenn der Arbeitsspeicher wie damals eingeschränkt ist), aber es gibt einen großen Unterschied zwischen X wird erleichtert durch Y "und" X benötigt Y ".
ein CVn
8
@ MichaelKjörling: "Bis Windows 95 haben es alle so gemacht" * - wirklich? Sogar auf * nix-Systemen, auf denen Motif in den 80ern ausgeführt wurde?
LarsH
@LarsH Guter Punkt, und einer, an den ich zu spät gedacht habe, um den Kommentar zu bearbeiten. Dies negiert jedoch nicht den Punkt: Es ist durchaus möglich, Single-Threaded-GUI-Anwendungen zu schreiben. Sie brauchen dafür kein Multithreading, obwohl es dem Programmierer einige Aufgaben (erheblich) erleichtert.
ein Lebenslauf
@ MichaelKjörling: Ich stimme zu, es negiert nicht deinen Punkt, der ein gültiger ist. (Ich glaube auch nicht, dass Upregos falsche Aussage seinen Standpunkt negiert.)
LarsH
Als Beispiel für das, was @ MichaelKjörling sagte, hatte Visual Basic (vor .NET) als Programmiersprache keine Multithreading-Unterstützung. Alles wurde auf einem einzigen Thread ausgeführt. Wenn Sie eine Benutzereingabe in der Mitte eines langen DoEventsVorgangs verarbeiten möchten, rufen Sie auf , wodurch die Nachrichtenwarteschlange verarbeitet wird. Dies geschieht jedoch im selben Thread und blockiert den langen Vorgang, bis alle Nachrichten verarbeitet wurden . (Natürlich können Sie Win32-API-Funktionen aufrufen und / oder zusätzliche Prozesse erstellen, aber zu diesem Zeitpunkt können Sie auch eine der untergeordneten Sprachen verwenden.)
Bob
5

Wir sollten zurücktreten und uns fragen: Wie kann ein Computer mit einer einzelnen CPU zwei Threads haben?

Threads sind Software-Entitäten, keine Hardware. Um einen anderen Thread zu haben, benötigen Sie nur Speicher für die Objekte, aus denen der Thread besteht, z. B. eine Deskriptorstruktur und einen Stapel.

Das Betriebssystem wechselt zu verschiedenen Zeiten zwischen Threads, z. B. innerhalb bestimmter Interrupts (z. B. eines Timer-Interrupts) oder wenn Threads Aufrufe an das Betriebssystem senden.

Von allen im System vorhandenen Threads befindet sich normalerweise nur eine Teilmenge in einem Zustand, der üblicherweise als "ausführbar" bezeichnet wird. Ausführbare Threads sind sehr lauffreudig: Sie werden entweder ausgeführt oder sitzen in einer "Ausführungswarteschlange" und warten darauf, vom Scheduler abgesetzt zu werden. Threads, die nicht ausgeführt werden können, werden "blockiert" und warten darauf, eine Ressource zu erhalten oder Eingaben zu erhalten, oder "schlafen", was dem Blockieren von Eingaben gleicht, wobei "Eingabe" der Zeitverlauf ist. Ein "Kontextwechsel" findet statt, wenn die Scheduler-Funktion im Betriebssystem einen Blick auf die Ausführungswarteschlange eines Prozessors wirft und einen anderen Thread zur Ausführung auswählt.

Lassen Sie sich nicht von "Hyperthreading" verwechseln , dem Namen von Intel für eine bestimmte Hardwarefunktion.

Kaz
quelle