2016-05-25 9 views
7

The documentation für runtime.LockOsThread Zustände:Warum sperrt Go's LockOSThread diesen Betriebssystem-Thread nicht?

LockOSThread Drähte des anruf goroutine zu seinem aktuellen Betriebssystem-Thread. Bis die aufrufende goroutine ExcludeOSThread beendet oder aufruft, wird sie immer in diesem Thread ausgeführt, und keine andere goroutine kann.

Aber betrachten Sie dieses Programm:

package main 

import (
    "fmt" 
    "runtime" 
    "time" 
) 

func main() { 
    runtime.GOMAXPROCS(1) 
    runtime.LockOSThread() 
    go fmt.Println("This shouldn't run") 
    time.Sleep(1 * time.Second) 
} 

Die main goroutine zum einem Thread verfügbar OS von GOMAXPROCS eingestellt verdrahtet ist, so würde ich erwarten, dass die goroutine auf Linie 3 erstellt von main werden nicht ausgeführt. Stattdessen druckt das Programm This shouldn't run, pausiert für 1 Sekunde und wird beendet. Warum passiert das?

Antwort

6

Vom runtime package documentation:

Die GOMAXPROCS variable begrenzt die Anzahl der Betriebssystem-Threads, die gleichzeitig auf Benutzerebene Go-Code ausführen kann. Es gibt keine Begrenzung für die Anzahl von Threads, die bei Systemaufrufen im Namen von Go-Code blockiert werden können. diese zählen nicht zum GOMAXPROCS-Limit.

Der Schlafgewinde trägt nicht zu dem GOMAXPROCS Wert von 1, so geht frei ist ein weiterer Thread haben die fmt.Println goroutine laufen.

+0

so die Frage 'Warum GoOS LockOSThread nicht diesen OS-Thread sperren?' Sollte 'warum mehrere goroutines ausgeführt werden, selbst wenn GOMAXPROCS auf 1 gesetzt ist' –

0

Das sieht für mich richtiges Verhalten aus. Von dem, was ich verstehe, bindet die LockOSThread() Funktion nur alle zukünftigen Anrufe an den einzelnen OS-Thread, es schläft nicht oder stoppt den Thread überhaupt.

Edit für Klarheit: das einzige, was LockOSThread() tut, ist Multithreading deaktivieren, so dass alle zukünftigen GO-Aufrufe in einem einzigen Thread passieren. Dies ist hauptsächlich für Dinge wie Grafik-APIs gedacht, die einen einzelnen Thread benötigen, um korrekt zu funktionieren.

Nochmals bearbeitet.

Wenn Sie vergleichen diese:

func main() { 
    runtime.GOMAXPROCS(6) 
    //insert long running routine here. 
    go fmt.Println("This may run almost straight away if tho long routine uses a different thread") 
} 

Um dies:

func main() { 
    runtime.GOMAXPROCS(6) 
    runtime.LockOSThread() 
    //insert long running routine here. 
    go fmt.Println("This will only run after the task above has completed") 
} 

Wenn wir legen Sie eine lange Laufroutine in der Lage oberhalb dann den ersten Block angedeutet kann fast sofort, wenn die lange laufen Routine läuft auf einem neuen Thread, aber im zweiten Beispiel muss immer auf den Abschluss der Routine gewartet werden.

+0

Zusätzliche Informationen: http://StackOverflow.com/Questions/25361831/benefits-of-Runtime-lockosthread-in-golang – sorifiend

+3

Aber die Dokumentation besagt, dass "* * no ** andere goroutines können "in diesem Thread ausführen. Das ist irreführende Dokumentation, wenn überhaupt. Ich beabsichtige nicht zu schlafen oder den OS-Thread anzuhalten, sondern zu verhindern, dass die Goroutine in Zeile 3 von main ausgeführt wird. – EMBLEM

+0

Ja, es ist ein wenig irreführend. Wenn Sie jedoch die Einfügung in der Mitte durchlesen, sagt es "Bis die aufrufende Goroutine -snip beendet- keine andere Goroutine" kann. Die Goroutine, von der gesprochen wird, bezieht sich auf etwas anderes, das Sie nach der Verwendung von 'LockOSThread()' ausführen. Es sollte möglicherweise "kann ausgeführt werden" am Ende dieses Dokuments. – sorifiend

1

Hier ist ein Windows-Beispiel, das Ihnen wahrscheinlich helfen wird zu verstehen, was vor sich geht. Es druckt Thread-IDs, auf denen Gououtines ausgeführt werden. Musste syscall verwenden, damit es nur unter Windows funktioniert. Aber Sie können es leicht auf andere Systeme portieren.

package main 

import (
    "fmt" 
    "runtime" 
    "golang.org/x/sys/windows" 
) 

func main() { 
    runtime.GOMAXPROCS(1) 
    runtime.LockOSThread() 
    ch := make(chan bool, 0) 
    go func(){ 
     fmt.Println("2", windows.GetCurrentThreadId()) 
     <- ch 
    }() 
    fmt.Println("1", windows.GetCurrentThreadId()) 
    <- ch 
} 

ich nicht schlafen Laufzeit zu verhindern, verwenden zum Schlafen goroutine anderen Thread Laichen. Der Kanal blockiert und entfernt die Goroutine aus der Warteschlange. Wenn Sie den Code ausführen, sehen Sie, dass die Thread-IDs unterschiedlich sind. Die Hauptgoroutine hat einen der Threads gesperrt, so dass die Runtime einen anderen erzeugen muss.

Wie Sie bereits wissen, verhindert GOMAXPROCS nicht, dass die Laufzeit mehr Threads erzeugt. GOMAXPROCS ist mehr über die Anzahl der Threads, die Gououtines parallel ausführen können. Es können jedoch mehr Threads für Goroutinen erstellt werden, die beispielsweise darauf warten, dass syscall beendet wird.

Wenn Sie runtime.LockOSThread() entfernen, sehen Sie, dass die Thread-IDs gleich sind. Das liegt daran, dass das Channel-Lesen die Goroutine blockiert und es der Laufzeit erlaubt, die Ausführung einer anderen Goroutine auszuführen, ohne einen neuen Thread zu erzeugen. So können mehrere Goroutinen gleichzeitig ausgeführt werden, selbst wenn 1 ist.

Verwandte Themen