2016-05-25 16 views
7

The documentation per runtime.LockOsThread stati:Perché LockOShread di Go not non blocca questo thread del sistema operativo?

fili LockOSThread il goroutine chiamando all'attuale thread di sistema operativo. Finché la goroutine di chiamata non si chiude o chiama Unlockosthread, verrà sempre eseguita in quel thread e nessun'altra goroutine può.

Ma considera questo programma:

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) 
} 

Il main goroutine è collegato a quello disponibile filo OS fissato dal GOMAXPROCS, quindi mi aspetterei che il goroutine creato sulla linea 3 della main non verrà eseguito. Ma invece il programma stampa This shouldn't run, si ferma per 1 secondo e si chiude. Perché succede?

risposta

6

Dal runtime package documentation:

La variabile GOMAXPROCS limita il numero di thread del sistema operativo che può eseguire a livello utente codice Go contemporaneamente. Non esiste un limite al numero di thread che possono essere bloccati nelle chiamate di sistema per conto del codice Go; quelli non contano rispetto al limite GOMAXPROCS.

filo Il sonno non conta verso il valore GOMAXPROCS di 1, quindi Go è libero di avere un altro thread eseguire il fmt.Println goroutine.

+0

quindi la domanda 'Perché non va LockOSThread bloccare questo thread del sistema operativo?' Dovrebbe essere "perché più goroutine vengono eseguite anche se GOMAXPROCS è impostato su 1' –

0

Sembra un comportamento corretto per me. Da quanto ho capito, la funzione LockOSThread() lega solo tutte le chiamate future al thread del sistema operativo singolo, non interrompe o interrompe il thread.

Modifica per chiarezza: l'unica cosa che LockOSThread() fa è disattivare il multithreading in modo che tutte le future chiamate GO si verifichino su un singolo thread. Questo è principalmente per l'uso con cose come le API grafiche che richiedono un singolo thread per funzionare correttamente.

Modificato di nuovo.

Se si confronta questo:

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") 
} 

A tal:

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") 
} 

Se inseriamo una lunga procedura corrente nella posizione indicata sopra quindi il primo blocco può essere eseguito quasi subito se il lungo la routine viene eseguita su un nuovo thread, ma nel secondo esempio dovrà sempre attendere il completamento della routine.

+0

Letture addizionali: http://stackoverflow.com/questions/25361831/benefits-of-runtime-lockosthread-in-golang – sorifiend

+3

Ma la documentazione afferma che "* * no ** altre goroutine possono "eseguire in quel thread. Questa è una documentazione fuorviante se non altro. Non intendo dormire o interrompere il thread del sistema operativo, ma impedisco l'esecuzione della goroutine sulla riga 3 del main. – EMBLEM

+0

Sì, è un po 'fuorviante. Tuttavia, se si legge l'inserto nel mezzo, si dice "Fino a quando non si esce dalla goroutine di chiamata -snip- non può farlo nessun'altra goroutine". La goroutine di cui parla si riferisce a qualcos'altro che si esegue dopo aver usato 'LockOSThread()'. Dovrebbe avere "può essere eseguito" alla fine di quel documento. – sorifiend

1

Ecco un esempio di Windows che probabilmente ti aiuterà a capire cosa sta succedendo. Stampa ID di thread su cui goroutine sono in esecuzione. Ho dovuto usare syscall in modo che funzioni solo su Windows. Ma puoi facilmente portarlo su altri sistemi.

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 
} 

Non utilizzo il sonno per impedire al runtime di generare un altro thread per la goroutine di sospensione. Il canale bloccherà e rimuoverà semplicemente goroutine dalla coda in esecuzione. Se esegui il codice vedrai che gli ID dei thread sono diversi. La goroutine principale ha bloccato uno dei thread in modo che il runtime debba generare un altro.

Come già sapete, GOMAXPROCS non impedisce al runtime di generare più thread. GOMAXPROCS è più sul numero di thread che possono eseguire goroutine in parallelo. Ad esempio, è possibile creare più thread per le goroutine che attendono il completamento di syscall.

Se rimuovi runtime.LockOSThread() vedrai che gli ID di thread sono uguali. Questo perché la lettura del canale blocca la goroutine e consente al runtime di fornire l'esecuzione a un'altra goroutine senza generare nuova discussione. È così che più goroutine possono essere eseguite simultaneamente anche quando GOMAXPROCS è 1.