goroutine 睡着了 - 死锁
goroutine asleep - deadlock
在下面的代码中,我试图生成 MaxOutstanding
个处理程序。每个处理程序循环遍历队列 queue
中的项目并将它们打印出来,我还将 true
写入 done
通道。
在我的主函数中,我启动处理程序并将 9 个元素写入 queue
并等待第一个元素写入 done
队列。
package main
import "fmt"
type Request struct {
int32
}
var MaxOutstanding = 5
func handle(queue chan *Request, i int, done chan bool) {
for r := range queue {
fmt.Println(i, "---", r)
done <- true
}
}
func Serve(clientRequests chan *Request, quit, done chan bool) {
// Start handlers
for i := 0; i < MaxOutstanding; i++ {
go handle(clientRequests, i, done)
}
<-quit // Wait to be told to exit.
}
func main() {
clientRequests := make(chan *Request)
quit := make(chan bool)
done := make(chan bool)
go Serve(clientRequests, quit, done)
clientRequests <- &Request{4}
clientRequests <- &Request{1}
clientRequests <- &Request{2}
clientRequests <- &Request{3}
clientRequests <- &Request{5}
clientRequests <- &Request{6}
clientRequests <- &Request{7}
clientRequests <- &Request{8}
clientRequests <- &Request{9}
fmt.Println( "...........>", <- done )
close(clientRequests)
close(done)
}
执行时出现以下错误。我看不出实施有什么问题,我什至要关闭频道。
4 --- &{4}
0 --- &{1}
1 --- &{2}
2 --- &{3}
3 --- &{5}
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send]:
main.main()
/home/ubuntu/digs-svc/src/digs/go1.go:45 +0x251
goroutine 5 [chan receive]:
main.Serve(0xc82004c060, 0xc82004c0c0, 0xc82004c120)
/home/ubuntu/digs-svc/src/digs/go1.go:28 +0x92
created by main.main
/home/ubuntu/digs-svc/src/digs/go1.go:37 +0xb9
goroutine 6 [chan send]:
main.handle(0xc82004c060, 0x0, 0xc82004c120)
/home/ubuntu/digs-svc/src/digs/go1.go:16 +0x23b
created by main.Serve
/home/ubuntu/digs-svc/src/digs/go1.go:25 +0x5b
编辑:
显然,fmt.Println("....", <- done)
不足以表示 done
频道有消费者。我在执行顺序中向上移动了代码。向消费者写入数据时,消费者需要在通道上 "listening"。在我之前的代码中,写入第一个数据时没有消费者。
工作代码。
您正在通过 done
通道上的发送阻止 handle 函数中通道的迭代,因为另一端没有接收任何东西。
那些额外的通道并没有真正做任何事情,你可以只添加一个 WaitGroup
来同步处理程序的退出,然后你可以删除 done
通道,这将允许处理程序继续.
func handle(queue chan *Request, i int, wg *sync.WaitGroup) {
defer wg.Done()
for r := range queue {
fmt.Println(i, "---", r)
}
}
func Serve(clientRequests chan *Request, wg *sync.WaitGroup) {
// Start handlers
for i := 0; i < MaxOutstanding; i++ {
wg.Add(1)
go handle(clientRequests, i, wg)
}
}
func main() {
clientRequests := make(chan *Request)
var wg sync.WaitGroup
go Serve(clientRequests, &wg)
for i := int32(0); i < 50; i++ {
clientRequests <- &Request{i}
}
close(clientRequests)
wg.Wait()
}
https://play.golang.org/p/oUFjZONjhk(请注意,在 playground 中,此示例目前似乎支持单个 goroutine 作为接收方。通常被阻塞的 goroutine 将随机接收,如果编译和 运行 通常)
在 for 循环中,您仅处理对第 5 个元素的通道操作,但是在 main 函数中,您试图将值发送到已关闭的通道。
要克服这种情况,您可以在 for 循环内发送请求值:
for i := 0; i < MaxOutstanding; i++ {
clientRequests <- &Request{int32(i)}
}
这是工作代码:
package main
import (
"fmt"
)
type Request struct {
int32
}
var MaxOutstanding = 10
func handle(queue chan *Request, i int, done chan bool) {
for r := range queue {
fmt.Println(i, "---", r)
done <- true
}
}
func Serve(clientRequests chan *Request, quit, done chan bool) {
// Start handlers
for i := 0; i < MaxOutstanding; i++ {
go handle(clientRequests, i, done)
}
<-quit // Wait to be told to exit.
}
func main() {
clientRequests := make(chan *Request)
quit := make(chan bool)
done := make(chan bool)
go Serve(clientRequests, quit, done)
for i := 0; i < MaxOutstanding; i++ {
clientRequests <- &Request{int32(i)}
}
fmt.Println("...........>", <-done)
close(clientRequests)
close(done)
}
在下面的代码中,我试图生成 MaxOutstanding
个处理程序。每个处理程序循环遍历队列 queue
中的项目并将它们打印出来,我还将 true
写入 done
通道。
在我的主函数中,我启动处理程序并将 9 个元素写入 queue
并等待第一个元素写入 done
队列。
package main
import "fmt"
type Request struct {
int32
}
var MaxOutstanding = 5
func handle(queue chan *Request, i int, done chan bool) {
for r := range queue {
fmt.Println(i, "---", r)
done <- true
}
}
func Serve(clientRequests chan *Request, quit, done chan bool) {
// Start handlers
for i := 0; i < MaxOutstanding; i++ {
go handle(clientRequests, i, done)
}
<-quit // Wait to be told to exit.
}
func main() {
clientRequests := make(chan *Request)
quit := make(chan bool)
done := make(chan bool)
go Serve(clientRequests, quit, done)
clientRequests <- &Request{4}
clientRequests <- &Request{1}
clientRequests <- &Request{2}
clientRequests <- &Request{3}
clientRequests <- &Request{5}
clientRequests <- &Request{6}
clientRequests <- &Request{7}
clientRequests <- &Request{8}
clientRequests <- &Request{9}
fmt.Println( "...........>", <- done )
close(clientRequests)
close(done)
}
执行时出现以下错误。我看不出实施有什么问题,我什至要关闭频道。
4 --- &{4}
0 --- &{1}
1 --- &{2}
2 --- &{3}
3 --- &{5}
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send]:
main.main()
/home/ubuntu/digs-svc/src/digs/go1.go:45 +0x251
goroutine 5 [chan receive]:
main.Serve(0xc82004c060, 0xc82004c0c0, 0xc82004c120)
/home/ubuntu/digs-svc/src/digs/go1.go:28 +0x92
created by main.main
/home/ubuntu/digs-svc/src/digs/go1.go:37 +0xb9
goroutine 6 [chan send]:
main.handle(0xc82004c060, 0x0, 0xc82004c120)
/home/ubuntu/digs-svc/src/digs/go1.go:16 +0x23b
created by main.Serve
/home/ubuntu/digs-svc/src/digs/go1.go:25 +0x5b
编辑:
显然,fmt.Println("....", <- done)
不足以表示 done
频道有消费者。我在执行顺序中向上移动了代码。向消费者写入数据时,消费者需要在通道上 "listening"。在我之前的代码中,写入第一个数据时没有消费者。
工作代码。
您正在通过 done
通道上的发送阻止 handle 函数中通道的迭代,因为另一端没有接收任何东西。
那些额外的通道并没有真正做任何事情,你可以只添加一个 WaitGroup
来同步处理程序的退出,然后你可以删除 done
通道,这将允许处理程序继续.
func handle(queue chan *Request, i int, wg *sync.WaitGroup) {
defer wg.Done()
for r := range queue {
fmt.Println(i, "---", r)
}
}
func Serve(clientRequests chan *Request, wg *sync.WaitGroup) {
// Start handlers
for i := 0; i < MaxOutstanding; i++ {
wg.Add(1)
go handle(clientRequests, i, wg)
}
}
func main() {
clientRequests := make(chan *Request)
var wg sync.WaitGroup
go Serve(clientRequests, &wg)
for i := int32(0); i < 50; i++ {
clientRequests <- &Request{i}
}
close(clientRequests)
wg.Wait()
}
https://play.golang.org/p/oUFjZONjhk(请注意,在 playground 中,此示例目前似乎支持单个 goroutine 作为接收方。通常被阻塞的 goroutine 将随机接收,如果编译和 运行 通常)
在 for 循环中,您仅处理对第 5 个元素的通道操作,但是在 main 函数中,您试图将值发送到已关闭的通道。
要克服这种情况,您可以在 for 循环内发送请求值:
for i := 0; i < MaxOutstanding; i++ {
clientRequests <- &Request{int32(i)}
}
这是工作代码:
package main
import (
"fmt"
)
type Request struct {
int32
}
var MaxOutstanding = 10
func handle(queue chan *Request, i int, done chan bool) {
for r := range queue {
fmt.Println(i, "---", r)
done <- true
}
}
func Serve(clientRequests chan *Request, quit, done chan bool) {
// Start handlers
for i := 0; i < MaxOutstanding; i++ {
go handle(clientRequests, i, done)
}
<-quit // Wait to be told to exit.
}
func main() {
clientRequests := make(chan *Request)
quit := make(chan bool)
done := make(chan bool)
go Serve(clientRequests, quit, done)
for i := 0; i < MaxOutstanding; i++ {
clientRequests <- &Request{int32(i)}
}
fmt.Println("...........>", <-done)
close(clientRequests)
close(done)
}