Tipp: Um Hyperthreading zu verstehen, sollte man sich erst den Abschnitt über Multitasking reinziehen.
Als Thread, das möchte ich vorausschicken, bezeichnet man einen "Programmfaden". Ich werde hier im Folgenden aber statt "Prozess" oder "Thread" einfach den Ausdruck "Programm" benutzen, das ist einfacher zu verstehen, wenn auch nicht 100%ig korrekt ausgedrückt. Die Techies unter euch werden es mir hoffentlich verzeihen.
Stellen wir uns vor, unser Prozessor wäre ein Supermarkt mit mehreren Abteilungen: Eine Abteilung für Mode und eine für Lebensmittel. Nun stellen wir uns weiter vor, der Architekt des Supermarktes hätte ihn so gebaut, dass immer nur entweder Lebensmittel gekauft werden könnten, oder Kleidung, weil nur eine Kasse drin ist und weil es wichtig wäre, dass die Kasse immer, wenn man einen neuen Schwung Kunden rein holt, komplett abgerechnet wird.
Nun, stellen wir uns vor, jede Gruppe von Kunden müsse glauben, dass sie den Laden für sich ganz alleine hat, weil sie beim Einkauf wie Hooligans verhalten und besser unter sich bleiben (in etwa, als wenn eine Gruppe Punker am Wühltisch auf eine Gruppe Kriegsveteranen aus dem Altersheim trifft - man hält sie besser auseinander, sonst gibt es Chaos).
Der Architekt hat noch ein Problem: Weil die Punks und die Kriegsveteranen nicht gerne warten und schnell Randale machen, müssen beide das Gefühl haben, dass sie prompt bedient werden (oder wartest du gerne auf bis du ein Programm beendet hast, damit du das nächste starten kannst? Natürlich nicht!). Also lässt man eine gewisse Anzahl Leute aus dem Altersheim in den Supermarkt, macht die Tür zu, stellt den Laden um und lässt dann ein paar von den Punks rein, macht wieder einen Kassensturz und holst wieder ein paar Kriegsveteranen. Das machst du solange, bis alle durch sind.
Das hört sich zwar haarsträubend an, ist aber genau die Art, wie bisherige Prozessoren gebaut wurden.
Jeder Prozessor (=Supermarkt) hat also mehrere Funktionseinheiten (=Modeabteilung, Lebensmittelabteilung), die möglichst parallel genutzt werden sollen. Reduzieren wir das mal der Einfachheit halber auf 2 Einheiten: Eine für Festkommaberechnung (ganze Zahlen) und eine für Fliesskomma-Berechnungen (Dezimalbrüche). Bei den Befehlen selbst kommt es (natürlich) auf die Reihenfolge an, im Gegensatz zum Supermarkt, wo es egal ist, ob zuerst Hinz oder Kunz einkauft. Nun hast du aber generell mehrere Programme (=Kundengruppen) auf einem Rechner laufen, die zwar alle ihr eigenes Ding durchziehen wollen, aber sich trotzdem einen Prozessor teilen müssen. Jetzt kommt es zu folgendem Fall: Programm A (die Gruppe aus dem Altersheim) hat x Befehle (=Kunden), genannt A1 bis Ax. Programm B (die Gruppe Punks) ebenso: B1 bis By.
Normalerweise würde das so gehen (das ist das Threading im üblichen Fall): Programm A arbeitet n Befehle (1 < n < x) lang und wird bei An unterbrochen (also nach Kunde n aus dem Altersheim), der derzeitige Prozessorstatus wird gerettet (=Kassenabrechnung) -> das braucht Zeit. B (=die Horde Punker) beginnt nun zu Arbeiten und rechnet froh in dem Prozessor rum, auch hier wird B irgendwann bei Befehl m (1 < m < y) unterbrochen (also nach Kunde m von den Punks), der Prozessorstatus wird gerettet (und bei diesem "Kassensturz" Zeit verschwendet), der Prozessorstatus von A wird rekonstruiert (= die Kasse wird in den Zustand versetzt, der nach Kunde n der ersten Gruppe vorlag), damit A weiter machen kann, wo es aufgehört hat, und A rechnet beim Befehl An+1 weiter, bis B wieder an die Reihe kommt.
Es ergeben sich also folgende Probleme: Erst einmal braucht so ein Prozesswechsel (=Kassenumstellung) immer Zeit, aber das ist aber nur halb so schlimm. Viel schlimmer ist es, dass während ein Programm auf der CPU arbeitet, ein anderes warten muss, obwohl es dort abeiten könnte, wo ein anderes Programm gerade nichts zu tun hat. Bzw.: wenn die Punks gerade die Bierreserven der Lebensmittelabteilung plündern, müssen die alten Herren und Damen vor dem Supermarkt warten, obwohl sie in der Zeit den Wühltisch mit den Hüten unsicher machen könnten.
Ein Supermarkt dieser Art wäre längst pleite gegangen.
Dem möchte man nun Abhilfe schaffen, zumindest zum Teil, also denkt man sich folgendes aus und nennt es:
Unser Supermarktarchitekt hat dazugelernt. Er hat nun für jede Abteilung eine Kasse eingerichtet, die getrennt abgerechnet werden kann. Ausserdem bringt er am Supermarkt 2 Namensschilder an, und schafft es durch diesen billigen Trick, der Stadt und beiden Gruppen Kunden vorzugaukeln, sie hätten jeweils ihren eigenen Supermarkt, obwohl es eigentlich nur einen Eingang gibt. Das bedeutet, auf den Prozessor umgemünzt, dass man nun den Status der Fliesskommaeinheit und der Festkommaeinheit getrennt sichern kann und dass dem Betriebsystem (=die Stadt), und damit den Programmen (=Kundengruppen), vorgespielt wird, dass zwei Prozessoren (=Supermärkte) im Computer sitzen.
Während die Kunden der ersten Gruppe, also Programm A, mit seinen Befehlen heftig z.B. in der Fliesskommaberechnung steckt, und die Festkomma Einheit völlig brach liegt, war es bisher normal, dass Programm B vielleicht irgendwelche Festkommabefehle abarbeiten könnte, aber auf seinen Prozesswechsel warten musste. Was macht man also? Nun, man spielt den Befehlen vor, dass jeder seine eigene CPU hat, wie sonst, nur nicht abwechselnd sondern gleichzeitig. Also kommen die Befehle von A und B gemischt in den Prozessor und der Prozessor überlegt sich nun, wie er die Dinger in die Funktionseinheiten schickt. Nehmen wir an, A braucht gerade die Fliesskommaeinheit, während B die Festkommaeinheit braucht. Man schickt beide nebeneinander rein, sorgt dafür, dass der Prozessorstatus von beiden Programmen dort, wo es sie interessiert, gesichert und rekonstruiert wird, da der Status der Fliesskommaeinheit für B nicht von Wichtigkeit ist, sondern andere Sachen, braucht man die zunächst nicht extra für B rekonstruieren, spart sich also hier etwas Zeit und kann A dort weiter arbeiten lassen. So arbeitet die CPU A und B gleichzeitig ab, bis es zu einem Problem kommt: A ist fertig mit Fliesskomma und braucht jetzt Festkomma, also die Funktionseinheit wo B gerade rumarbeitet. In diesem Fall muss halt A auf B warten und es kommt zum klassischen, wechselseitigen Ausschluss: B wird unterbrochen und der Prozessorstatus dort gerettet, wo es B wichtig ist und der Status der Festkommaeinheit (und mehr) von A wird rekonstruiert, und zwar so, dass A nun weiter machen kann, wo es irgendwann mal mit Festkomma aufgehört hatte, was man sich bisher für A sparen konnte, weil A da im Moment nichts tun wollte.
Das Ganze macht man nun nicht nur mit 2 Programmen, sondern mit einer Menge, die je nach Design der CPU unterschiedlich sein kann (Es kann schliesslich auch mehr als nur 2 Hyperthreading Kanäle geben), aber so **ungefähr** läuft das.
Hyperthreading verbessert die Auslastung eines Prozessors, weil es dafür sorgt, dass die einzelnen Funktionseinheiten des Prozessors weniger Zeit mit Warten verplempern. Wenn man einen Prozessor mit einer Wasserleitung vergleicht, so könnte man sagen, dass Hyperthreading ein System sei, dass dafür sorgt, dass in der Leitung weniger Luftblasen sind und damit mehr Wasser fliessen kann.
Es ergibt sich mit Hyperthreading jedoch ein Problem: das Betriebssystem muss mehrere Prozessoren unterstützen. Ein Betriebssystem hat einen sogenanten "Scheduler" (sprich "Skedjuler"), ein Programm das dafür sorgt, dass andere Programme Rechenzeit auf dem Prozessor bekommen. Eben dieser Scheduler muss wissen, dass es in einem Rechner mehr als nur einen Prozessor gibt, und wissen, wann er am besten welchem Programm welchen Prozessor zuteilen sollte. Wer also Windows98 fährt, sollte sich nicht wundern, wenn er durch Hyperthreading keinen Geschwindigkeits-Schub bekommt, denn der Scheduler von Windows9x kennt nur eine CPU. Mit WindowsNT, WindowsXP professional, einem aktuellem Linux oder Solaris kann man jedoch von der neuen Technologie profitieren.
Der Einwand, den man an in Punkto Hyperthreading immer wieder hört ist: "Hyperthreading ist SMP für Arme!" (SMT = Symmetric Multi Processing). Wer so urteilt, hat nur in einem gewissen Rahmen Recht und er verkennt den Zweck von Hyperthreading. Es geht beim Hyperthreading nicht primär darum, Threads möglichst parallel laufen zu lassen, sondern es versucht die Auslastung der einzelnen CPU zu optimieren. Die Information, was nun auf dem Chip parallel ausgeführt werden darf, liefert dabei die Thread-Eigenschaft. Die Aufteilung in virtuelle CPUs ist daher lediglich ein Kunstgriff, um unabhängige Threads eindeutig voneinander zu trennen. Klassisches SMP (Symmetric Multi-Processing, Prozesse parallel ausführen) versucht das System schneller zu machen, indem man 2 Prozessoren unabhängig voneinander rechnen lässt - im Vergleich zum Hypterthreading sind das 2 unterschiedliche Ansätze und auch unterschiedliche Ziele, die für das Betriebsystem jedoch gleich aussehen. SMP mit mehreren echten Prozessoren ist natürlich performanter, weil es weniger wechselseitige Ausschlüsse gibt, als beim Hyperthreading, doch schliessen sich beide Techniken nicht aus. Es ist z.B. nach wie vor möglich, einen Dual-Prozessor Rechner mit 2 Hyperthreading-fähigen CPUs auszustatten, statt mit konventionellen CPUs. Das Betriebsystem meint dann zwar 4 Prozessoren zu haben, tatsächlich hat es jedoch 2 eigenständige CPUs mit jeweils gesteigertem Durchsatz.
Ein anderer, auch von echten Multiprozessorsystemen bekannter Einwand ist, dass nicht jedes Programm mehrere Threads benutzt und nicht jedes Problem sich parallelisieren lässt und sowieso würden meisten Programme nur auf eine einzelne CPU zugeschnitten sein und daher gar nicht davon profitieren. Bei genauerer Betrachtung ist aber auch dieser Einwand nur eingschränkt richtig, denn auf einem modernen Multitasking-System (also einem System, das scheinbar mehrere Programme gleichzeitig ausführt), laufen immer mehrere Prozesse. Auch wenn ein Programm seine Aufgabe nicht auf 2 Prozessoren verteilen kann, so wird es doch in seiner Arbeit weniger von anderen Programmen behindert, da diese auf 2 Prozessoren verteilt werden und so ein Programm, das in einem Ein-Prozessor System stören würde, u.U. gerade vom anderen Prozessor abgearbeitet wird. Gleiches gilt natürlichauch für Hypertreading, nur halt viel eingeschränkter. Dennoch ist der Einwand auch nicht unsinnig, denn wenn man sich mal ansieht, wie die Systemauslastung so aussieht, so fällt auf, dass es zwar normalerweise viele Prozesse gibt, aber die meisten von ihnen schlafen, so dass sie das Hauptprogramm gar nicht all zu sehr behindern.