met*_*eto 0 concurrency go goroutine
我有一个列表,其中包含一个弹出元素的函数,以及另一个"接收"弹出元素的函数.我认为接收器关闭后会关闭通道,但似乎该程序在到达之前已经死锁.这是最好的方法吗?我应该有另一个通道来检测弹出窗口何时完成?
func pop(list *[]int, c chan int) {
if len(*list) != 0 {
result := (*list)[0]
*list = (*list)[1:]
fmt.Println("about to send ", result)
c <- result
} else {
return
}
}
func receiver(c chan int) {
result := <-c
fmt.Println("received ", result)
}
var list = []int{1, 2, 3}
func main() {
fmt.Println("Main")
c := make(chan int)
go pop(&list, c)
go pop(&list, c)
for len(list) > 0 {
receiver(c)
}
close(c) //Dosen't seem to have any effect
fmt.Println("done")
}
Run Code Online (Sandbox Code Playgroud)
代码有很多问题,让我们看看.
pop
访问切片时,您的函数不会锁定,因此这就是数据竞争.for len(list) > 0 {}
是一个数据竞赛,因为您在其他2个goroutine中修改它时访问列表.for len(list) > 0 {}
将永远不会返回,因为您的列表中有3个项目,但您只调用pop两次.receiver(c)
由于#3的错误,它试图从频道读取,但没有任何写入它.一种方法是使用一个writer(pop
)和多个reader(receiver
):
func pop(list *[]int, c chan int, done chan bool) {
for len(*list) != 0 {
result := (*list)[0]
*list = (*list)[1:]
fmt.Println("about to send ", result)
c <- result
}
close(c)
done <- true
}
func receiver(c chan int) {
for result := range c {
fmt.Println("received ", result)
}
}
var list = []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
func main() {
c := make(chan int)
done := make(chan bool)
go pop(&list, c, done)
go receiver(c)
go receiver(c)
go receiver(c)
<-done
fmt.Println("done")
}
Run Code Online (Sandbox Code Playgroud)
go run -race blah.go
在弄乱goroutines时总是使用.