2013-07-25 6 views
23

Goroutines sind leichte Prozesse, die von der Go-Laufzeit automatisch auf einen oder mehrere Betriebssystem-Threads aufgeteilt werden. (Dies ist eine wirklich cool Funktion von Go!)Wie kann mein Go-Programm alle CPU-Kerne beschäftigt halten?

Angenommen, ich habe eine gleichzeitige Anwendung wie ein Webserver. In meinem hypothetischen Programm gibt es viele Dinge gleichzeitig, ohne viel nicht-gleiches (Amdahl'sches Gesetz) Verhältnis.

Es scheint, dass die Standardanzahl der verwendeten Betriebssystem-Threads derzeit 1 ist. Bedeutet dies, dass nur ein CPU-Kern verwendet wird?

Wenn ich beginne mein Programm mit

runtime.GOMAXPROCS(runtime.NumCPU()) 

Willen, die vernünftigerweise effiziente Nutzung von geben alle die Kerne auf meinem PC?

Gibt es irgendeine "parallele Schlaffheit", die von noch mehr OS-Threads in Gebrauch ist, z. über einige Heuristik

runtime.GOMAXPROCS(runtime.NumCPU() * 2) 

?

Antwort

33

Vom Go FAQ:

Warum nicht Multi-goroutine Programm verwenden, um mehrere CPUs?

Sie müssen die Shell-Umgebungsvariable GOMAXPROCS festlegen oder die gleichnamige Funktion des Laufzeitpakets verwenden, damit die Laufzeitunterstützung mehr als einen Betriebssystemthread verwenden kann.

Programme, die eine parallele Berechnung durchführen, sollten von einer Erhöhung von GOMAXPROCS profitieren. Beachten Sie jedoch, dass Parallelität keine Parallelität ist.

(UPDATE 2015.08.28: Go 1.5 gesetzt, um den Standardwert von GOMAXPROCS die gleiche wie die Anzahl der CPUs auf dem Computer zu machen, so sollte dies kein Problem mehr sein)

Und

Warum macht die Verwendung von GOMAXPROCS> 1 manchmal mein Programm langsamer?

Es hängt von der Art Ihres Programms ab. Probleme, die an sich sequentiell sind, können nicht durch Hinzufügen weiterer Gatorutins beschleunigt werden. Parallelität wird nur dann zur Parallelität, wenn das Problem intrinsisch parallel ist.

In der Praxis werden Programme, die mehr Zeit mit der Kommunikation auf Kanälen als mit Berechnungen verbringen, bei der Verwendung mehrerer Betriebssystem-Threads zu Leistungseinbußen kommen. Dies liegt daran, dass das Senden von Daten zwischen Threads einen Wechsel von Kontexten erfordert, was erhebliche Kosten verursacht. Zum Beispiel hat das Prime-Sieb-Beispiel aus der Go-Spezifikation keine signifikante Parallelität, obwohl es viele Goroutines startet; Das Erhöhen von GOMAXPROCS verlangsamt es eher als es zu beschleunigen.

Go's Goroutine Scheduler ist nicht so gut wie es sein muss. In Zukunft sollte es solche Fälle erkennen und seine Verwendung von OS-Threads optimieren. Vorläufig sollte GOMAXPROCS für jede Anwendung festgelegt werden.

Kurz gesagt: Es ist sehr schwierig, Go "effiziente Nutzung aller Ihrer Kerne" zu machen. Einfach eine Milliarde Goroutines hervorzubringen und GOMAXPROCS zu erhöhen, ist genauso wahrscheinlich, Ihre Leistung zu verschlechtern, als es zu beschleunigen, weil es Gewindekontexte die ganze Zeit wechseln wird. Wenn Sie ein großes Programm haben, das parallelisierbar ist, dann funktioniert es gut, GOMAXPROCS auf die Anzahl paralleler Komponenten zu erhöhen. Wenn Sie ein paralleles Problem in ein weitgehend nicht paralleles Programm eingebettet haben, kann es schneller werden, oder Sie müssen möglicherweise Funktionen wie runtime.LockOSThread() kreativ nutzen, um sicherzustellen, dass die Laufzeitumgebung alles korrekt verteilt (in der Regel wird Go nur dumpf gespreizt) derzeit nicht blockierende Goroutines willkürlich und gleichmäßig unter allen aktiven Threads).

Auch GOMAXPROCS ist die Anzahl der CPU-Kerne zu verwenden, wenn es größer ist als NumCPU Ich bin ziemlich sicher, dass es einfach an NumCPU klemmt. GOMAXPROCS entspricht nicht unbedingt der Anzahl der Threads. Ich bin nicht 100% ig sicher, wann genau die Laufzeit entscheidet, neue Threads zu erzeugen, aber eine Instanz ist, wenn die Anzahl der blockierenden goroutines mit runtime.LockOSThread() größer oder gleich GOMAXPROCs ist - es wird mehr Threads als Kerne erzeugen Damit kann der Rest des Programms ordnungsgemäß ausgeführt werden.

Grundsätzlich ist es ziemlich einfach, GOMAXPROCS zu erhöhen und verwenden alle Kerne Ihrer CPU zu machen. Es ist eine andere Sache an dieser Stelle in Go's Entwicklung, es tatsächlich zu Smart smart und effizient alle Kerne Ihrer CPU zu bekommen, die eine Menge Programm-Design und Finling erfordern, um richtig zu machen.

+0

Ihr vorletzter Absatz scheint falsch zu sein. http://golang.org/pkg/runtime/ –

+0

Ich weiß, was Laufzeit sagt, ich anders hier gesagt wurde: https://groups.google.com/forum/#!topic/golang-nuts/z_7F6EpcCLY Vielleicht hängt es von der Implementierung ab? – LinearZoetrope

+0

Ah! Das ist ein nützlicher Thread. "Es gibt ein Argument dafür, dass der Go-Scheduler immer einen Ersatzthread für kurzfristige Anfragen bereithält.Wenn keine laufende goroutine die Kontrolle in den letzten N Millisekunden aufgegeben hat, führen Sie einen neuen Thread aus, anstatt auf zu warten, damit die compute-gebundenen beendet werden. Ein Thread pro CPU ist keine gute Regel, wenn es compute-gebundene Aufgaben gibt. "Also, ein paar überschüssige Threads wäre in diesem Fall ratsam. –

0

runtime.GOMAXPROCS() legt die Anzahl der (virtuellen) CPU-Kerne fest, die Ihr Programm gleichzeitig verwenden kann. Wenn Go mehr CPU-Kerne verwenden kann, als Sie tatsächlich haben, hilft das nicht, da Ihr System nur über so viele CPU-Kerne verfügt.

Um in mehr als einem Thread zu laufen, muss Ihr Programm mehrere Goroutinen haben, typischerweise Funktionsaufrufe mit go someFunc(). Wenn Ihr Programm keine zusätzlichen goroutines startet, läuft es natürlich nur in einem Thread, egal wie viele CPUs/Kerne Sie verwenden dürfen.

Schauen Sie sich this und die folgenden Übungen zum Erstellen von goroutines.

+1

Erlauben Go mehr OS-Threads als es gibt CPUs können manchmal die Latenz reduzieren, da es "mehr bereit sein könnte" zu laufen, wenn einer der Threads blockiert werden sollte, jedoch nur kurz. –

+0

@ Rick-777: Sicher. Die Einstellung 'runtime.GOMAXPROCS' ändert nicht die Anzahl der Threads Das Programm kann jedoch ausgeführt werden. Es ändert die Anzahl der CPUs, auf denen diese Threads ausgeführt werden können. Überprüfen Sie 'runtime.NumGoroutine', um zu sehen, wie viele Threads/goroutines Ihr p Programm ist entstanden. – sjakobi

3

Diese Frage kann nicht beantwortet werden, sie ist viel zu weit gefasst.

Nehmen Sie Ihr Problem, Ihren Algorithmus und Ihre Arbeitsbelastung und messen Sie, was für diese Kombination am besten ist.

Niemand kann eine Frage wie "Gibt es eine Heuristik, die Zugabe von doppelt so viel Salz zu meinem Mittagessen wird es besser schmecken?" Da dies vom Mittagessen abhängt (Tomaten profitieren viel mehr von Salz als von Erdbeeren) ist Ihr Geschmack und wie viel Salz es schon gibt. Versuch es.

auf mehr: runtime.GOMAXPROCS(runtime.NumCPU()) hat Kultstatus, aber die Anzahl der Threads durch Steuern der GOMAXPROCS Umgebungsvariable aus der außerhalb Einstellung könnte die viel bessere Option sein.

+0

Sicherlich haben Menschen Erfahrungen mit dem Schreiben von Webservern und ähnlichen hochgradig parallelen Apps gesammelt? –

Verwandte Themen