5

Golang两个协程交替输出

 3 years ago
source link: https://studygolang.com/articles/35057
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Golang两个协程交替输出

jlvihv · 7天之前 · 449 次点击 · 预计阅读时间 2 分钟 · 大约8小时之前 开始浏览    

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

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK