2016-06-21 39 views
2

等待上sync.Waitgroup我有下面的代碼從下面的goroutine信道發送時進入僵局:在延遲

package main 

import (
    "fmt" 
    "sync" 
) 

func main() { 
    for a := range getCh(10) { 
     fmt.Println("Got:", a) 
    } 
} 

func getCh(n int) <-chan int { 
    var wg sync.WaitGroup 
    ch := make(chan int) 
    defer func() { 
     fmt.Println("closing") 
     wg.Wait() 
     close(ch) 
    }() 
    wg.Add(1) 
    go func() { 
     defer wg.Done() 
     for i := 0; i < n; i++ { 
      ch <- i 
     } 
    }() 
    wg.Add(1) 
    go func() { 
     defer wg.Done() 
     for i := n; i < 0; i-- { 
      ch <- i 
     } 
    }() 

    return ch 
} 

我知道,這是合法的defer使用wg.Wait()。但是我一直無法在通道作爲返回值的函數中找到用處。

回答

4

我認爲你所犯的錯誤是你認爲deferred函數也會異步運行。但情況並非如此,因此getCh()將在其延遲部分中阻塞,等待WaitGroup。但是,由於沒有人從頻道讀取,寫入它的goroutine無法返回,因此WaitGroup導致死鎖。嘗試這樣的:

func getCh(n int) <-chan int { 
    ch := make(chan int) 
    go func() { 
     var wg sync.WaitGroup 
     wg.Add(1) 
     go func(n int) { 
      defer wg.Done() 
      for i := 0; i < n; i++ { 
       ch <- i 
      } 
     }(n) 
     wg.Add(1) 
     go func(n int) { 
      defer wg.Done() 
      for i := n; i > 0; i-- { 
       ch <- i 
      } 
     }(n) 
     wg.Wait() 
     fmt.Println("closing") 
     close(ch) 
    }() 

    return ch 
} 
+0

完美。非常感謝。 – abhink

+0

另一種我大量使用自己的方法:https://play.golang.org/p/RjsB3-EOQI。這使用了一個「更接近」的程序來阻塞和關閉,而不是像你期望的延遲函數一樣工作,但是是一個單獨的goroutine。 – Kaedys

1

由於您沒有使用任何緩衝通道,因此您的通道看起來像阻塞。看看這個簡單的例子https://play.golang.org/p/zMnfA33qZk

ch := make(chan int, n)

該通道塊還記得,當他們被填充。我不確定你的代碼的目標是什麼,但看起來你正在使用緩衝通道。這是一個有效的好作品https://golang.org/doc/effective_go.html#channels

接收器總是阻塞,直到有數據要接收。如果通道未經緩衝,則發送器阻塞,直到接收器收到該值。如果通道有一個緩衝區,發送方只會阻塞該值直到該值被複制到緩衝區;如果緩衝區已滿,這意味着要等到某個接收者已經檢索到一個值。

+0

基本上我想要一個函數,返回一個通道讀取多個進程(由上述兩個循環表示)。我想在關閉通信通道('ch')之前等待它們兩個完成。接受你的建議,我爲這個頻道增加了一個足夠大的緩衝區,現在看起來問題是即使wg.Wait()處於推遲狀態,它也會阻止函數返回到main的執行狀態。我會用這些評論來更新這個問題。 – abhink