英文:
deadlock with double channel
问题
我正在尝试创建一个程序,将字符串发送到一组goroutine(通过通道)。一旦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
循环。我错了吗(因为代码发生了死锁)?
我该如何解决这个死锁问题?
谢谢你的回答。
英文:
I'm trying to create a program that send strings to a pool of goroutines (through a channel). Once the goroutine have finish their job, they send some results (through an other channel).
The code is:
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()
}
Running echo "something" | ./main
cause a deadlock.
From what I've understood, close(lCh)
should stop the for url := range linkChan
loop. Am I wrong (it seems so since the code deadlock) ?
How can I resolve this deadlock ?
Thank you for your answers.
答案1
得分: 4
你需要在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)
}
这样就可以正常工作了。
英文:
You need to pump the urls in a goroutine, otherwise the outCh
will fill up which as you aren't emptying it. This will stall all the workers and it will deadlock.
So re-arrange the code to look like this
go func() {
for _, link := range urls {
lCh <- link
}
close(lCh)
wg.Wait()
close(outCh)
}()
for res := range outCh {
fmt.Printf("%s\n", res)
}
And it will work fine
答案2
得分: 0
你在关闭 outCh
之前使用了 range
。你需要在 wg.Wait()
之后关闭 outCh
,就像 Nick 的回答中那样。
英文:
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.
You use range
before close outCh
. You have to close outCh
after wg.Wait()
, like in Nick`s answer.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论