考虑下面的玩具示例。代码完美无缺,但当你交换标记为replace
的2行时,会出现死锁。当你有不同数量的发送和接收时,是否有更好的方法来处理这种情况?
package main
import "fmt"
import "strconv"
func main() {
a := make(chan string)
b := make(chan string)
go func() {
for i := 0; i < 2; i++ {
go func(i int) {
fmt.Println(<-a)
b <- strconv.Itoa(i) + "b" // replace
a <- strconv.Itoa(i) + "a" // replace
}(i)
}
}()
a <- "0"
for i := 0; i < 2; i++ {
fmt.Println(<-b)
}
}
编辑:使用select语句,select a
有可能被选中,而且仍无法防止死锁,因为goroutines无法执行
package main
import "fmt"
import "strconv"
func main() {
a := make(chan string)
b := make(chan string)
c := make(chan bool)
cancel := make(chan bool)
go func() {
for i := 0; i < 2; i++ {
go func(i int) {
fmt.Println(<-a)
b <- strconv.Itoa(i) + "b" // replace
a <- strconv.Itoa(i) + "a" // replace
c <- true
}(i)
}
}()
go func() {
<-c
<-c
cancel <- true
}()
a <- "0"
loop:
for {
select {
case ain := <-a:
fmt.Println("select", ain)
case bin := <-b:
fmt.Println("select", bin)
case <-cancel:
break loop
}
}
}
答案 0 :(得分:2)
使用选择:
package main
import "fmt"
import "strconv"
func main() {
a := make(chan string)
b := make(chan string)
go func() {
for i := 0; i < 2; i++ {
go func(i int) {
fmt.Println(<-a)
b <- strconv.Itoa(i) + "b" // replace
a <- strconv.Itoa(i) + "a" // replace
}(i)
}
}()
// regardless of which comes in first, this will handle it
select {
case ain <- a:
fmt.Println("sent a", ain)
case bin <- b:
fmt.Println("sent b", bin)
case <- cancel:
break
}
}
该示例将对a或b频道上发送的项目进行阻止和阻止。
我可以选择设置取消令牌或超时。
您的原始代码在交换机上发生死锁,因为您发送了B,您只是在那里收听A. Golang要求您在发送之前先在频道上收听。这是多个渠道的模式,不知道您将首先获得哪个渠道。