2013-11-22 72 views
2

有兩件奇怪的事情。奇怪的事情當處理goroutine

  1. 我在切片中做了1000個數字,但它只是打印246,爲什麼是246?爲什麼不是1000?

  2. 如果我刪除「log.Println(」hey「)」這一行,爲什麼它只打印0?

我知道它可能有同步問題,但我之前沒有寫過任何併發程序,所以任何文章都可以推薦?

import (
     "log" 
     "runtime" 
) 

func main() { 

    count := 1000 
    slice := make([] int,count) 
    for i := 0; i <= count-1; i++ { 
    slice[i] =i 
    } 
    for _,v := range slice{ 
    go echo(v) 
    } 
    log.Println("hey")//if delete this line,it just print 0 
    runtime.Gosched() 
} 


func echo(v int) { 
    log.Println(v) 
} 

回答

3

不能保證任何go例程在主例程完成之前運行。當主程序完成時,程序退出而不等待你創建的所有程序完成(甚至啓動)。

解決此問題的最簡單方法是分配一個同步通道,將其傳遞給每個回顯實例,並在日誌語句後向其寫入一個令牌。然後主線程在返回之前應該讀取count令牌。

+0

但我在最後叫runtime.Gosched(),在main()應該等到別人夠程回來吧? –

+2

@MaxLau,不,它不是那樣的。 'runtime.Gosched()'簡單地要求調度程序將控制流傳遞給其他goroutine,但是當其他goroutine也調用'runtime.Gosched()'或做一個等價物時它永遠不會阻止控制流返回到'main'在調度方面的行動。所以實際上你的'Gosched()'調用會導致其他的goroutine運行一段時間,然後主goroutine再次運行,在此之後不久終止。 –

3

如果您退出主程序,它不會等待任何正在運行的程序。您需要同步正在運行的常規程序,根據我的經驗,sync.WaitGroup是正確的通用解決方案。

Playground

import (
    "log" 
    "sync" 
) 

func main() { 

    count := 1000 
    slice := make([]int, count) 
    for i := 0; i <= count-1; i++ { 
     slice[i] = i 
    } 
    wg := new(sync.WaitGroup) 
    for _, v := range slice { 
     wg.Add(1) 
     go echo(v, wg) 
    } 
    wg.Wait() 
} 

func echo(v int, wg *sync.WaitGroup) { 
    defer wg.Done() 
    log.Println(v) 
} 
+0

thx夥計,但爲什麼我不能使用runtime.Gosched()在main()的結尾?它說「Gosched產生處理器,允許其他goroutines運行。」 –

+0

'runtime.Gosched()'只會短暫產生處理器 - 當main()恢復時它將返回並且main go例程將退出,從而導致所有後臺例程失效。 –