Golang两个协程交替输出


本文摘自网络,作者jlvihv,侵删。

题目:

现在有两个goroutine。

一个输出1、3、5、7、9……

另一个输出2、4、6、8、10……

写一段代码,让他们输出1、2、3、4、5、6、7、8、9、10……

解法:

使用Go的channel来解决比较合适。

需要3个channel。

A通道用来记录A协程的状态。

B通道用来记录B协程的状态。

Exit通道用来阻塞主协程,使程序不要立即退出,而是等待我们发出退出信号以后才退出。

Go的channel具有阻塞特性,无缓冲通道中只能存放一个数据。

通道最初是空的,如果想从空通道中读取一个数据,程序就会阻塞,直到向通道中写入一个数据。

如果通道中有一个数据,却没有人来读,程序也将阻塞,直到有人将这个数据读走。

利用这个特性,我们在主goroutine中读取Exit通道,因为我们还没有向Exit通道中写数据,主goroutine将在此阻塞。

主goroutine虽然阻塞了,其他goroutine却是可以正常运行的。

我们设计,其他goroutine把自己的工作都做完之后,向Exit通道写入一个数据。

主goroutine得到这个数据之后,程序不再阻塞,就可以正常退出了。

这样我们就实现了最基本的,有多个goroutine时,工作没做完时等待,都做完后退出的功能了。

然后我们来设计AB两个通道。

利用无缓冲通道阻塞的特性,我们设计:

A协程输出一个数后,向B通道写入一个数据。

B协程输出一个数后,也向A通道写入一个数据。

AB都会时刻检测自己的通道中有没有数据,但是就像接力棒一样,只有另一个协程可以向当前协程的通道传递数据。

而且传递完之后必须等待。

这就保证了,A干活的时候,B必须等着,不能跟A抢活干。

A干完之后,权利交给B,B干完之后,权利再交给A,直到俩人都把活干完。

这就是AB协程交替输出的中间过程,我们还需要设计开始和结束。

开始时,我们在主goroutine中,手动向A协程发送一个开始的信号。

结束时,最后一个把活干完的人(B),向Exit通道中发送一个数据,使主goroutine退出。

实现代码:

package main

import (
  "fmt"
)

func main() {
  // 创建3个channel,A,B和Exit
  A := make(chan bool)
  B := make(chan bool)
  Exit := make(chan bool)

  go func() {
    // 如果A通道是true,我就执行
    for i := 1; i <= 10; i += 2 {
      if ok := <-A; ok {
        fmt.Println("A 输出", i)
        B <- true
      }
    }
  }()

  go func() {
    defer func() { Exit <- true }() // 这个协程的活干完之后,向主goroutine发送信号
    // 如果B通道是true,我就执行
    for i := 2; i <= 10; i += 2 {
      if ok := <-B; ok {
        fmt.Println("B 输出", i)
        if i != 10 { // r如果i等于10了,就不要再向A通道写数据了,否则将导致A通道死锁,至于为什么,坦白说我很疑惑
          A <- true
        }
      }
    }
  }()

  A <- true // 启动条件
  <-Exit    // 结束条件
}


相关阅读 >>

详解Golang数组的传递

Golang项目如何部署到linux服务器

slice

手撸Golang spring ioc/aop 之2

ubuntu怎么安装配置Go语言环境

Go是不是动态类型语言

双链表 哈希 Go 实现lfu 缓存算法

Golang 如何判断文件是否存在

Golang底层是c语言吗?

Golang json乱码解决方法

更多相关阅读请进入《Go》频道 >>




打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,您说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

分享从这里开始,精彩与您同在

评论

管理员已关闭评论功能...