Golang两个协程交替输出

jlvihv · · 2314 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

题目: 现在有两个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退出。 实现代码: ```go 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 // 结束条件 } ```

有疑问加站长微信联系(非本文作者))

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

2314 次点击  ∙  1 赞  
加入收藏 微博
2 回复  |  直到 2021-06-07 10:49:51
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传