当前位置: 首页 > news >正文

协程执行顺序引发的问题

引言

在Golang中,因为协程执行的顺序是不固定的,如果不在代码里进行控制,可能就会导致预期外的输出。
本文通过分析一段代码的执行来介绍这种情况,以及可行的控制协程执行顺序的方法:

  1. sleep()
  2. waitGroup

实例分析

代码

func NewRingBuffer(inCh, outCh chan int) *ringBuffer {return &ringBuffer{inCh:  inCh,outCh: outCh,}
}type ringBuffer struct {inCh  chan intoutCh chan int
}func (r *ringBuffer) Run() {for v := range r.inCh {select {case r.outCh <- v:default:<-r.outCh // pop one item from outchanr.outCh <- v}}close(r.outCh)
}func main() {inCh := make(chan int)outCh := make(chan int, 4)rb := pkg.NewRingBuffer(inCh, outCh)go rb.Run()for i := 0; i < 10; i++ {inCh <- i}close(inCh)//time.Sleep(time.Millisecond * 50)for res := range outCh {fmt.Println(res)}
}

上面代码的作用是,声明ringBuffer环状缓冲区;主协程往inCh写10个数的同时,有一个协程异步的读取数据,并写到outCh中;
outCh是一个4缓冲区大小的channel,如果outCh没满就直接写入,否则把outCh的首部元素移除再添加;
因此,预期输出应该是:6、7、8、9。
但实际的输出是:5、6、7、8、9。

分析

多出来的“5”,是因为协程的执行顺序不可控,当主协程执行到

for i := 0; i < 10; i++ {inCh <- i
}close(inCh)

时,此时outCh中是5、6、7、8;run协程还没有继续执行,就开始遍历outCh:

for res := range outCh {fmt.Println(res)
}

然后输出阻塞后,run协程才继续执行,把9写到outCh中,因此最后的输出结果是5、6、7、8、9.

解决办法

sleep()

使用sleep()函数,能让当前协程让出CPU,暂停执行一段时间。
对于这种方法,可以对上面函数进行如下改造:

close(inCh)
time.Sleep(time.Millisecond * 50)
// 新增
for res := range outCh {fmt.Println(res)
}

WaitGroup

使用waitGroup可以实现协程间通信,对于这段例子,通过wg保证run()函数执行完后,在对outCh进行输出。
改造方法如下:

func (r *ringBuffer) RunWithWg(wg *sync.WaitGroup) {defer wg.Done()for v := range r.inCh {select {case r.outCh <- v:default:<-r.outCh // pop one item from outchanr.outCh <- v}}close(r.outCh)
}func TestRaceWithWg(t *testing.T) {inCh := make(chan int)outCh := make(chan int, 4)rb := pkg.NewRingBuffer(inCh, outCh)var wg sync.WaitGroupwg.Add(1)go rb.RunWithWg(&wg)go func() {for i := 0; i < 10; i++ {inCh <- i}close(inCh)}()wg.Wait()for res := range outCh {fmt.Println(res)}
}
http://www.lryc.cn/news/380242.html

相关文章:

  • android webview调用js滚动到指定位置
  • WPF 深入理解一、基础知识介绍
  • 腾讯云点播ugc upload | lack signature 问题处理
  • 计算机视觉实验二:基于支持向量机和随机森林的分类(Part one: 编程实现基于支持向量机的人脸识别分类 )
  • 5.什么是C语言
  • DINO-DETR
  • Representation RL:HarmonyDream: Task Harmonization Inside World Models
  • Centos7系统下Docker的安装与配置
  • 无人机校企合作
  • 八爪鱼现金流-028,个人网站访问数据统计分析,解决方案
  • 大厂面试官问我:布隆过滤器有不能扩容和删除的缺陷,有没有可以替代的数据结构呢?【后端八股文二:布隆过滤器八股文合集】
  • PHP米表域名出售管理源码带后台
  • 【开发12年码农教你】Android端简单易用的SPI框架-——-SPA
  • 以太坊==MetaMask获取测试币最新网址
  • 军用FPGA软件 Verilog语言的编码准测之触发器、锁存器
  • 智能汽车 UI 风格独具魅力
  • javafx例子笔记
  • 【ajax基础】回调函数地狱
  • SparkSQL的分布式执行引擎-Thrift服务:学习总结(第七天)
  • 联华集团:IT团队如何实现从成本中心提升至价值中心|OceanBase 《DB大咖说》(十)
  • 计算机系统基础实训五—CacheLab实验
  • PHP框架之CodeIgniter框架
  • 714. 买卖股票的最佳时机含手续费
  • Linux系统查看程序内存及CPU占用
  • 数据结构7---图
  • Excel 如何复制单元格而不换行
  • 前端 CSS 经典:mix-blend-mode 属性
  • OpenCV--滤波器(一)
  • MK的前端精华笔记
  • 低代码平台框架:开源选型、实践与应用深度解析