2013-04-02 19 views
24

Nel tutorial GO, abbiamo questa diapositiva:Perché è necessario time.sleep per eseguire determinate goroutine?

http://tour.golang.org/#62

package main 

import (
    "fmt" 
    "time" 
) 

func say(s string) { 
    for i := 0; i < 5; i++ { 
     time.Sleep(100 * time.Millisecond) 
     fmt.Println(s) 
    } 
} 

func main() { 
    go say("world") 
    say("hello") 
} 

risultati esecuzione di questo codice produce previsto ("mondo" e "ciao" scritto sullo schermo intercambiabile 5 volte).

Tuttavia, se commentare time.Sleep (e, di conseguenza, la linea "time" del importazione) ed eseguire il programma ancora una volta, ci ritroviamo con solo "ciao" visualizzate sullo schermo per cinque volte.

Che cosa è così importante su time.Sleep che salva la goroutine dalla morte?

risposta

29

Se si rimuove il time.Sleep, non si dà la possibilità alla goroutine say("world") di correre. Lo schedulatore di goroutine non è preventivo. Le tue goroutine devono abbandonare il controllo prima che possa scappare un'altra goroutine. Un modo per rinunciare al controllo è eseguire time.Sleep.

Se si prende la time.Sleep dalla funzione say poi il goroutine primario viene eseguito 5 volte senza rinunciare al controllo al goroutine secondaria e poi, quando le primarie ritorna goroutine dal say il programma esce perché non c'è nulla per mantenere il programma vivo .

7

Poiché lo schedulatore di goroutine non è preventivo, le tue goroutine devono abbandonare il controllo prima che venga eseguita un'altra goroutine. Un modo per rinunciare al controllo è con time.Sleep. Un altro modo è con runtime.Gosched().

Ecco il tutorial modificati per utilizzare Gosched(): http://play.golang.org/p/jQ9mlGYXXE

Questa è una lezione utile per capire goroutines. Tuttavia, provare a controllare direttamente lo scheduler è sicuramente un anti-pattern; il dolore seguirà spesso.

Invece, pensa di più alle goroutine come blocchi di hardware digitale in comunicazione (le macchine a stati sono una buona analogia). È meglio conoscere il modello Communicating Sequential Processes su cui si basano le goroutine. In un progetto basato su CSP, ogni goroutine ha il suo stato privato e scambia messaggi per interagire con lo stato di altre goroutine. Il passaggio dei messaggi impone la sincronizzazione, che viene utilizzata dallo scheduler per determinare quale attività ottiene il tempo della CPU e cosa viene messo in attesa.

Quando ti avvicini a Vai in questo modo, probabilmente non dovrai mai preoccuparti delle parti interne dello scheduler.

+1

Il risultato che ottengo con 'runtime.Gosched()' è leggermente diverso. Prendo 5: ciao e 4: mondo. Mentre con 'time.Sleep()' ottengo 5 di ciascuno. – Akavall

1

Se si rimuove time.Sleep dalla funzione di dire il principale eseguirà dire ("ciao") e terminerà senza eseguire la goroutine. Se si aggiunge un'ora.Sleep (o in alternativa un selezionare {}) prima della fine principale darà tempo alla goroutine per l'esecuzione e quel thread verrà selezionato dallo scheduler.

Esempio:

package main 

import (
    "fmt" 
    "time" 
) 

func say(s string) { 
    for i := 0; i < 5; i++ { 
     // time.Sleep(100 * time.Millisecond) 
     fmt.Println(s) 
    } 
} 

func main() { 
    go say("world") 
    say("hello") 

    time.Sleep(1*time.Second) 
    // Vs: 
    // select {} // blocks indefinitely, requires manual interrupt 
      // In CSP-speak the empty select is like STOP. 
      // for{} would cause the cpu to max and the process's STATE will be `running` 
      // select{} will not cause the cpu to max and the process state will be `sleeping` 
} 

L'uscita sarà solitamente 5 ciao seguito da 5 mondo ma potrebbe anche riuscire a stampare uno dei mondo prima dell'ultima ciao

PROVA IT -> (http: //) goo.gl/K2v7H0

Problemi correlati