Go channel实现顺序无限输出123123123...

分析:

顺序:需要同步,无 buffer channel 正好可以实现;

无限:主协程阻塞,子协程为 deamon,或者说无限循环;

需要开3个线程(协程),

  • 一个线程用来输出1,无限输出
  • 一个线程用来输出2,无限输出
  • 一个线程用来输出3,无限输出

实现无限输出 123123123...

package main

import (
        "fmt"
        "time"
)

func print(curCh chan struct{}, nextCh chan struct{}, idx int64) {
        for{
                curCh<- struct{}{}    // 3
                fmt.Println(idx + 1)
                time.Sleep(time.Second)    // 方便人来观察,放慢打印输出的速度
                <-nextCh    // 4
        }
}

func main() {
        chs := []chan struct{}{make(chan struct{}), make(chan struct{}), make(chan struct{})}    // 5

        for i := 0; i < len(chs); i++ {    // 7
                go print(chs[i], chs[(i + 1) % len(chs)], int64(i))    // 6
        }

        <-chs[0]    // 2
        select{}    // 1
}

上面的代码里边,可以说是每行代码都有用处,一行都不能少。实现上也可以换一种同步的方式,变换下 channel 的接收和发送状态,有兴趣自己修改下即可。

先有个大概的理解,

<-chs[0],这是注释 5 中定义的 chan 数组的第一个元素,想象一下接力赛,一个队有 n 个人,n 个队友在固定位置准备就绪(这里起了3个无限循环的子协程),阻塞(等待)在那里(注释3),发令枪响起,第一个队友拿到令牌开始起跑(注释2),其他选手处于阻塞状态,等待前一个队友的接力,前一个队友完成了交接给下一个队友(注释4),下一个选手开始起跑。一直到最后一个队友跑完,是为输出一遍。假设接力赛无限循环,就能达到无限循环输出的状态。

看下输出结果,脑补下满屏的123...

注释 1:

select{} 语句,用于阻塞主协程,如果要实现无限执行子协程,主协程必须阻塞,而且在主协程阻塞时,必须要有活动的子协程,否则会报 deadlock。

做下实验,不阻塞主协程,主协程退出,子协程也不会打印输出,

把 print 函数中的 for 语句注释掉执行,只能输出一遍,继续往下执行时由于没有活着的子协程了,select 报 deadlock。加上无限循环可以保证子协程一直处于活动状态。

注释 2:

<-chs[0],发令枪响起,第一个队友拿到令牌开始起跑,其他选手处于阻塞状态,等待前一个队友的接力。

注释3:

curCh<- struct{}{},接力成功,解除阻塞状态,开始起跑。

注释4:

<-nextCh,接力给下个队友...循环

注释6和7:

起 n 个无限循环的协程,就是给接力赛征召 n 个队员,这里n=3。取模的方式可以达到环形状态。

Have Fun

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值