目录
在使用channel时使用select,当有一个channel有数据可读可写时,会执行对应的case分支
这样就可以避免channel死锁以及监听多个chennel
1、实现死锁
将channel变为无缓冲,并且只有生产者没有消费者
func send(ch chan<- int) {
for i := 0; i < 10; i++ {
ch <- i
}
fmt.Println("发送完成数据")
close(ch)
}
// func receive(ch <-chan int, wg *sync.WaitGroup) {
// defer wg.Done()
// for data := range ch {
// time.Sleep(1 * time.Second)
// fmt.Println("接收数据:", data)
// }
// }
func main() {
var wg sync.WaitGroup
ch := make(chan int)
wg.Add(1)
go send(ch)
//go receive(ch, &wg)
wg.Wait()
}
会进行报错:fatal error: all goroutines are asleep - deadlock!
2、修改生产者
加入case与default语句
func send(ch chan<- int) {
for i := 0; i < 10; i++ {
select {
case ch <- i:
fmt.Println("发送消息")
default:
fmt.Println("队列空间不足")
}
}
fmt.Println("发送完成数据")
close(ch)
}
// func receive(ch <-chan int, wg *sync.WaitGroup) {
// defer wg.Done()
// for data := range ch {
// time.Sleep(1 * time.Second)
// fmt.Println("接收数据:", data)
// }
// }
func main() {
//var wg sync.WaitGroup
ch := make(chan int)
//wg.Add(1)
send(ch)
//go receive(ch, &wg)
//wg.Wait()
}
最终输出结果:
队列空间不足
队列空间不足
队列空间不足
队列空间不足
队列空间不足
队列空间不足
队列空间不足
队列空间不足
队列空间不足
队列空间不足
发送完成数据
3、加入work
修改生产者
func send(ch chan<- int) {
i := 0
for {
time.Sleep(1 * time.Second)
select {
case ch <- i:
i++
}
}
}
加入work
func work(ch <-chan int, wg *sync.WaitGroup) {
tiker := time.NewTicker(2 * time.Second)
defer wg.Done()
for {
time.Sleep(500 * time.Millisecond)
select {
case data := <-ch:
fmt.Println("接收数据", data)
case <-tiker.C:
fmt.Println("执行上报")
default:
fmt.Println("队列为空")
}
}
}
修改main方法
func main() {
var wg sync.WaitGroup
ch := make(chan int)
wg.Add(1)
go send(ch)
go work(ch, &wg)
wg.Wait()
}
最终结果:
队列为空
接收数据 0
队列为空
接收数据 1
执行上报
接收数据 2
队列为空
接收数据 3
执行上报
接收数据 4
队列为空
解释:当队列为空时执行default,当接收到数据时返回数据,添加tiker定时器,设置每两秒执行一次打印执行上报以此循环