双通道死锁

deadlock with double channel

我正在尝试创建一个将字符串发送到 goroutines 池(通过通道)的程序。 goroutine 完成工作后,它们会发送一些结果(通过其他渠道)。

密码是:

package main

import "fmt"
import "os"
import "sync"
import "bufio"

func worker(linkChan <-chan string, outChan chan<- string, wg *sync.WaitGroup, jobId int) {
   defer wg.Done()

   for url := range linkChan {
    // ...
     outChan <- url
   }
}

func main() {
    lCh := make(chan string)
    wg := new(sync.WaitGroup)
    outCh := make(chan string)

    urls := []string{}
    if len(os.Args) > 1 {
        for _, link := range os.Args[1:] {
            urls = append(urls, link)
        }
    } else {
        s := bufio.NewScanner(os.Stdin)
        for s.Scan() {
            urls = append(urls, s.Text())
        }
    }

    num_worker := 10

    for i := 0; i < num_worker; i++ {
        wg.Add(1)
        go worker(lCh, outCh, wg, i)
    }
    for _, link := range urls {
        lCh <- link
    }
    close(lCh)

    for res := range outCh {
        fmt.Printf("%s\n", res)
    }
    close(outCh)
    wg.Wait()

}

运行 echo "something" | ./main造成死锁。

据我了解,close(lCh) 应该会停止 for url := range linkChan 循环。我错了吗(自代码死锁以来似乎是这样)?

我该如何解决这个僵局?

感谢您的回答。

您需要在 goroutine 中提取 url,否则 outCh 会填满,因为您没有清空它。这将拖延所有的工人,它会死锁。

所以重新安排代码看起来像这样

go func() {
    for _, link := range urls {
        lCh <- link
    }
    close(lCh)
    wg.Wait()
    close(outCh)
}()

for res := range outCh {
    fmt.Printf("%s\n", res)
}

它会很好用

Complete code

https://golang.org/ref/spec#For_range :

For channels, the iteration values produced are the successive values sent on the channel until the channel is closed. If the channel is nil, the range expression blocks forever.

您使用 range before 关闭 outCh。您必须在 wg.Wait() 之后关闭 outCh,就像 Nick 的回答一样。