我有一个无法解决的死锁问题。
我拥有一些网址,goroutine中的每个网址都会带给我足够的数据。我将这些数据放在一个通道中。但是,如果我关闭通道,程序将无法运行,如果我离开通道,则会出现死锁。
我不知道该怎么解决,有人会解决的
下面我以简化的方式提出问题
package main
import (
"fmt"
)
type urlNumbers struct {
url string
numbers []int
}
func getNumbers(urls []urlNumbers) chan int {
ch := make(chan int)
for _, url := range urls {
go allNumbersOfURL(url, ch)
}
return ch
}
func allNumbersOfURL(url urlNumbers, ch chan int) {
for _, i := range url.numbers {
ch <- i
}
}
func main() {
url1 := urlNumbers {url: "1", numbers: []int{1, 2, 3}}
url2 := urlNumbers {url: "2", numbers: []int{4, 5, 6}}
url3 := urlNumbers {url: "3", numbers: []int{7, 8, 9}}
url4 := urlNumbers {url: "4", numbers: []int{10, 11, 12}}
c := getNumbers([]urlNumbers{url1, url2, url3, url4})
for i := range c {
fmt.Println(i)
}
fmt.Println("END")
}
输出
go run app.go
10
11
12
4
7
1
2
3
5
6
8
9
fatal error: all goroutines are asleep - deadlock!
答案 0 :(得分:2)
您正在使用for i := range c
遍历一个通道,但是代码不知道何时停止。频道上的range
等待频道关闭或永久挂起。这就是为什么会出现僵局。
在通过该通道发布所有“ URL”之后,您应该关闭您的通道。可以通过sync.WaitGroup
的帮助来实现。在getNumbers
的循环之前,您可以使用WaitGroup
并设置要等待的作业数为len(urls)
:
wg:=&sync.WaitGroup{}
wg.Add(len(urls))
并在返回ch
之前添加一个新的goroutine:
go func() {
wg.Wait()
close(ch)
} ()
然后在allNumbersOfURL
中,将WaitGroup
添加为新参数,并在循环后设置完成的工作。
func allNumbersOfURL(url urlNumbers, ch chan int,wg *sync.WaitGroup) {
for _, i := range url.numbers {
ch <- i
}
wg.Done()
}
答案 1 :(得分:2)
通道必须关闭,您可以使用sync.WaitGroup
等待任务完成。这是对功能getNumbers
func getNumbers(urls []urlNumbers) <-chan int {
ch := make(chan int)
wg := &sync.WaitGroup{}
for _, url := range urls {
wg.Add(1)
go func(url urlNumbers, ch chan<- int) {
defer wg.Done()
allNumbersOfURL(url, ch)
}(url, ch)
}
go func(wg *sync.WaitGroup, ch chan int) {
wg.Wait()
close(ch)
}(wg, ch)
return ch
}
另外,我建议您在传递参数时使用通道方向。
可选的<-运算符指定通道方向,发送或 接收。如果没有给出方向,则该信道是双向的。