Go中按次序交替打印1212...,你知道它背后的设计模式吗

简介: Go中按次序交替打印1212...,你知道它背后的设计模式吗

让你goroutine交替打印1212...



首先这道题看似是两个goroutine交替打印,实则是有很多细节需要考虑,而且背后的设计模式就是生产者消费者模式


代码演示下简单的生产者消费者模式:


package main
import "fmt"
func main() {
 done := make(chan bool) //控制结束退出的信号
 ch := make(chan int) //chan通信 控制同步阻塞的
 go func() {
  for i:=1; i<=2; i++ {
   //生产
   ch <- 0
   fmt.Println("1")
  }
  //发送结束之后退出
  done <- true
 }()
 go func() {
  for i:=1; i<=2; i++ {
   //消费
   <- ch
   fmt.Println("2")
  }
 }()
 <-done
}
输出:
1
1
2
2


但是题目是让两个goroutine交替输出1212...而且还必须保证次序,比如A goroutine是永远打印1,B goroutine永远打印2 这样循环2次,输出结果应该是1212。


那么为什么上面的代码输出是1122呢?因为我们控制了开始的次序,但是并没有控制结束的次序,发生了并发不安全的情况。


当然你不能说这种方式就不适合别的场景,比如交替打印奇偶数,就增加一个条件判断就行:


package main
import "fmt"
func main() {
 done := make(chan bool) //控制结束退出的信号
 ch := make(chan int) //chan通信 控制同步阻塞的
 go func() {
  for i:=1; i<=5; i++ {
   //生产
   ch <- 0
   if i % 2 == 0 {
    fmt.Println("A ", i)
   }
  }
  //发送结束之后退出
  done <- true
 }()
 go func() {
  for i:=1; i<=5; i++ {
   //消费
   <- ch
   if i % 2 != 0 {
    fmt.Println("B ", i)
   }
  }
 }()
 <-done
}
输出:
B  1
A  2
B  3
A  4


B永远输出奇数,A永远输出偶数,它们交替打印。


好了言归正传,那我们如何写出并发安全的生产者消费者代码呢?我们用首尾两个chan交替释放控制权就可以解决这个问题,请看代码:


package main
import "fmt"
func main() {
 done := make(chan bool) //控制结束退出的信号
 chStart := make(chan int) //chan通信 控制起始同步阻塞的
 chEnd := make(chan int) //chan通信 控制结尾同步阻塞的
 go func() {
  for i:=1; i<=2; i++ {
   //生产 控制起始
   chStart <- 0
   fmt.Println("A ", 1)
   //暂停 等待结尾信号
   <-chEnd
  }
  //发送结束之后退出
  done <- true
 }()
 go func() {
  for i:=1; i<=2; i++ {
   //消费 结束起始
   <- chStart
   fmt.Println("B ", 2)
   //发送结尾信号
   chEnd <- 0
  }
 }()
 //阻塞等待退出信号
 <-done
}
输出:
A  1
B  2
A  1
B  2


现在可以看出来,输出的结果是正确的。为什么这么操作呢?就是当生产者生产之后把自己阻塞,等待消费者消费,消费者消费完成之后发送信号唤醒生产者继续生产,而消费者自己又被阻塞等生产者唤醒,其实这就是典型的生产者消费者模式。


小结


用两个chan实现按次序交替非常有意思,它背后的设计模式生产者消费者模式,大家可以在项目中使用起来,如果你觉得这篇文章对你有帮助,欢迎关注点赞转发哦。

相关文章
|
8天前
|
设计模式 Go 网络安全
[设计模式 Go实现] 结构型~代理模式
[设计模式 Go实现] 结构型~代理模式
|
9天前
|
设计模式 Go
[设计模式 Go实现] 结构型~享元模式
[设计模式 Go实现] 结构型~享元模式
|
9天前
|
设计模式 Go API
[设计模式 Go实现] 结构型~外观模式
[设计模式 Go实现] 结构型~外观模式
|
9天前
|
设计模式 Go
[设计模式 Go实现] 结构型~组合模式
[设计模式 Go实现] 结构型~组合模式
|
9天前
|
设计模式 Go
[设计模式 Go实现] 结构型~装饰模式
[设计模式 Go实现] 结构型~装饰模式
|
9天前
|
设计模式 Go
[设计模式 Go实现] 结构型~适配器模式
[设计模式 Go实现] 结构型~适配器模式
|
9天前
|
设计模式 Go
[设计模式 Go实现] 行为型~解释器模式
[设计模式 Go实现] 行为型~解释器模式
|
9天前
|
设计模式 Go
[设计模式 Go实现] 行为型~迭代器模式
[设计模式 Go实现] 行为型~迭代器模式
|
9天前
|
设计模式 存储 Go
[设计模式 Go实现] 行为型~备忘录模式
[设计模式 Go实现] 行为型~备忘录模式
|
9天前
|
设计模式 Go
[设计模式 Go实现] 行为型~中介者模式
[设计模式 Go实现] 行为型~中介者模式