2015-02-24 96 views
3
package main 

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

func main() { 
    intInputChan := make(chan int, 50) 
    var wg sync.WaitGroup 
    for i := 0; i < 3; i++ { 
     wg.Add(1) 
     go worker(intInputChan, wg) 
    } 
    for i := 1; i < 51; i++ { 
     fmt.Printf("Inputs. %d \n", i) 
     intInputChan <- i 
    } 
    close(intInputChan) 
    wg.Wait() 
    fmt.Println("Existing Main App... ") 
    panic("---------------") 
} 

func worker(input chan int, wg sync.WaitGroup) { 
    defer func() { 
     fmt.Println("Executing defer..") 
     wg.Done() 
    }() 

    for { 
     select { 
     case intVal, ok := <-input: 
      time.Sleep(100 * time.Millisecond) 
      if !ok { 
       input = nil 
       return 
      } 
      fmt.Printf("%d %v\n", intVal, ok) 

     default: 
      runtime.Gosched() 
     } 
    } 

} 

拋出的錯誤是。爲什麼所有的goroutines都睡着了 - 僵局。識別瓶頸

致命錯誤:所有goroutines都睡着了 - 僵局!

夠程1 [semacquire]: 同步(* WaitGroup).Wait(0xc082004600) C:/go/src/sync/waitgroup.go:132 +量0x170 main.main() E:/圍棋/go_projects/go/src/Test.go:22 + 0x21a

+1

而不是寫'無功WG的sync.WaitGroup''寫WG:=新(sync.WaitGroup)',你永遠不會再次犯這個錯誤! – 2015-02-24 09:49:54

+0

-1:[有些問題仍然存在問題,即使它們符合上面列出的其中一個類別:尋求調試幫助的問題(「爲什麼代碼不工作?」)必須包含所需的行爲,特定的問題或錯誤以及在問題本身中重現它所需的最短代碼。沒有明確問題陳述的問題對其他讀者沒有用處](http://stackoverflow.com/help/on-topic) – Vector 2015-04-23 21:30:17

回答

8

我剛試過(playground),通過wg *sync.WaitGroup,它工作。

傳遞sync.WaitGroup手段使sync.WaitGroup的副本(路過值):所述夠程提到Done()不同sync.WaitGroup

var wg sync.WaitGroup 
for i := 0; i < 3; i++ { 
    wg.Add(1) 
    go worker(intInputChan, &wg) 
} 

注意&wg:你是按值指針傳遞到原來的sync.WaitGroup,對於夠程使用。

3

如所提到的,不從同步繞包傳值的類型,右靠近sync package documentation的頂部:「含有在此包中定義的類型值不應該被複制。」這也包括類型(sync.Mutex,sync.WaitGroup等)。

然而,有幾個注意事項:

  • ,如果你知道你會多少添加(但如記錄,確保其完成之前什麼都可以撥打Wait您可以使用剛剛wg.Add單個呼叫)。
  • 你不想打電話給runtime.Gosched那樣;它使工人忙碌的循環。
  • 您可以使用range從通道讀取,以便在關閉時簡化停機。
  • 對於小函數,您可以使用閉包,而不必費神通過頻道或等待組。

那它變成這樣:

package main 

import (
    "fmt" 
    "sync" 
    "time" 
) 

func main() { 
    const numWorkers = 3 

    c := make(chan int, 10) 
    var wg sync.WaitGroup 

    wg.Add(numWorkers) 
    for i := 0; i < numWorkers; i++ { 
     go func() { 
      defer func() { 
       fmt.Println("Executing defer…") 
       wg.Done() 
      }() 

      for v := range c { 
       fmt.Println("recv:", v) 
       time.Sleep(100 * time.Millisecond) 
      } 
     }() 
    } 

    for i := 1; i < 51; i++ { 
     fmt.Println("send:", i) 
     c <- i 
    } 
    fmt.Println("closing…") 
    close(c) 

    fmt.Println("waiting…") 
    wg.Wait() 
    fmt.Println("Exiting Main App... ") 
} 

playground

+0

謝謝VonC&Dave將它改爲引用類型完成了這項工作。 – VimleshS 2015-02-24 08:55:18

+0

我喜歡你提到的所有筆記。你能否爲第3點(範圍從通道讀取)拋出一些更多的理論,或者指針也可以提供幫助。 – VimleshS 2015-02-24 09:39:08