Golang两个协程交替输出


题目:

现在有两个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    // 结束条件
}


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM