2013-04-02 40 views
24

在GO教程中,我們有這個幻燈片:爲什麼運行某些goroutines需要time.sleep?

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

運行這段代碼產生預期的結果(「世界」和「你好」寫到屏幕上交替5次)。

但是,如果我們註釋掉time.Sleep(因此,在"time"線進口的),然後運行程序再次,我們剩下的只有「你好」寫於屏幕的五倍。

關於time.Sleep這麼重要的事情,可以節省goroutine的死亡時間嗎?

回答

29

如果您刪除time.Sleep您不給say("world") goroutine一個機會運行。 goroutine調度程序不是搶先式的。在另一個goroutine運行之前,你的goroutines必須放棄控制權。放棄控制的一種方法是運行time.Sleep

如果從say功能取出time.Sleep則主夠程運行5次,不放棄控制到二次夠程,然後從say初級夠程返回程序退出時,因爲沒有什麼保持程序活着。

7

因爲goroutine調度程序不搶佔,您的goroutine必須在另一個goroutine運行之前放棄控制權。一種放棄控制的方法是time.Sleep。另一種方法是與runtime.Gosched()

下面是修改爲使用Gosched()教程:http://play.golang.org/p/jQ9mlGYXXE

這是理解夠程有益的一課。但是,試圖直接控制調度器肯定是一種反模式;悲傷往往會隨之而來。

相反,想想更多關於像通信數字硬件塊(狀態機是一個很好的比喻)的大塊的goroutines。最好了解goroutines所基於的Communicating Sequential Processes模型。在基於CSP的設計中,每個goroutine都有其自己的私有狀態並交換消息以與其他goroutine的狀態進行交互。消息的傳遞會強制同步,調度程序使用該同步來確定獲取cpu時間的活動以及放入等待隊列的內容。

當您以這種方式進行Go時,您可能永遠不需要擔心調度程序內部。

+1

結果我得到'runtime.Gosched()'略有不同。我得到5:你好,4:世界。 while'time.Sleep()'我得到每個5。 – Akavall

1

如果您從say函數中刪除time.Sleep,main將執行say(「hello」)並終止而不執行goroutine。如果在主結束前添加time.Sleep(或其他選擇{}),它將給goroutine運行時間並從調度程序中選擇該線程。

例子:

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

輸出通常是5 你好其次是5 世界但它也可以管理的最後提前打印世界之一你好

TRY IT - >(HTTP://)goo.gl/K2v7H0

相關問題