脚本之家,脚本语言编程技术及教程分享平台!
分类导航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服务器之家 - 脚本之家 - Golang - Go并发的方法之goroutine模型与调度策略

Go并发的方法之goroutine模型与调度策略

2021-12-08 10:50朱骥伦 Golang

在go中,协程co-routine被改为goroutine,一个goroutine只占几kb,因此可以有大量的goroutine存在,另一方面goroutine 的调度器非常灵活,本文给大家介绍下Go并发的方法之goroutine模型与调度策略,感兴趣的朋友一起看看吧

学习刘丹冰《8小时转职golang工程师》,本节都是原理

单进程操作系统

早期的单进程操作系统,可以理解为只有一个时间轴,cpu顺序执行每一个进程/线程,这种顺序执行的方式,cpu同一时间智能处理一个指令,一个任务一个任务去处理

这样就会导致进程阻塞的话,cpu就会卡在当前进程,一直在等待,cpu就会浪费

多线程/多进程操作系统

cpu利用轮询机制,调度各个进程,每个进程都分配固定的时间片,这个时间片很小,先执行进程a,如果a结束了,那没问题切换到下一进程b,但如果时间片内a没结束,cpu不管a没结束,会强制切换到下一进程b,以此类推,cpu就避免了阻塞在某一进程

但这样的问题是,在频繁切换进程的过程中,进程的切换就必然会导致切换成本,例如保存当前线程状态,系统调用,环境的上下文切换,各种拷贝复制就会导致时间浪费,大部分时间都用在切换了,进程数量越多,切换的浪费就越大

因此软件的目标就是提高cpu利用率

另一方面,进程的内存占用也是很大的问题

1:n模型

程序员的任务就是在用户态调接口,开发业务,内核态负责调硬件,调系统资源,用户线程和内核线程一一绑定,cpu只需要管内核线程,这样的内核线程称为thread,用户线程称为co-routine,thread通过管理协程调度器,管理多个协程,这样cpu还是只管理一个线程

Go并发的方法之goroutine模型与调度策略

这样就在用户态实现了并发,cpu也不用切换了,只用在协程切换时消耗很少的资源,解决了cpu高消耗调度的问题

这样的弊端是有一个协程阻塞了,下一个协程就不能执行了

m:n模型

m个线程通过协程调度器,管理多个协程,cpu的调度优化我们没法做,这个协程调度器就非常重要了

goroutine

在go中,协程co-routine被改为goroutine,一个goroutine只占几kb,因此可以有大量的goroutine存在,另一方面goroutine 的调度器非常灵活

goroutine早期调度器

早期的goroutine调度器有一个全局的goroutine队列,这个队列有一个锁,每个线程要创建、销毁、运行一个goroutine都要先获取一个锁,然后执行goroutine,执行完毕后再把锁还回去

这样的问题是激烈的锁竞争

另一方面,当一个线程执行一个goroutine时,这个goroutine新创建了一个goroutine,为了保证并发,这个新goroutine肯定得执行,这个新创建的就被放在下一个线程去执行,这实际上不满足程序的局部性原理

另外系统在频繁调用不同的线程还是会造成系统开销

gmp

在操作系统中,有一个操作系统调度器,用来调度cpu,来处理不同的内核线程,在这之上每个线程有一个处理器,这个处理器里有goroutine的各种资源,堆、栈、数据等,这样的处理器称为p,每个p管理一个自己的本地队列,这个队列里存放着这个p要处理的goroutine,goroutine要被处理时,线程获取一个p,p调度出一个goroutine交给线程,线程对goroutine进行处理,除了p的本地队列外,还有一个全局队列,里面也存放着要运行的goroutine

Go并发的方法之goroutine模型与调度策略

调度器设计策略

 复用线程

work stealing

当一个线程正在执行一个goroutine时,并且它的p本地队列里还有待执行的goroutine,别的p空闲的话就会帮它的线程偷取一个goroutine

Go并发的方法之goroutine模型与调度策略

↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

Go并发的方法之goroutine模型与调度策略

hand off

如果说一个p正执行的goroutine突然阻塞了,比如在等待输入之类的,那么这时候这个p的线程,也就是这个cpu实际上没有被利用,这时候就会创建/唤醒一个新的线程,这时候让阻塞的goroutine继续阻塞,当前cpu变为睡眠状态,但把物理cpu切换走到不阻塞的线程上,其余的p和p的本地队列直接被转移到新的线程上控制,如果之前的阻塞routine又不阻塞了,那把这个goroutine又加入到别的队列后
Go并发的方法之goroutine模型与调度策略

↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

Go并发的方法之goroutine模型与调度策略

并行

p的数量可以宏定义,例如为cpu核心数/2

抢占

在1:1模型中,一个协程和一个线程绑定,当有别的协程需要运行时,当前的协程除非释放出这个线程资源,否则新来的就只能等着

而goroutine的机制是,每个goroutine只有10ms,时间用完后新的goroutine一定会抢占这个cpu,没有谁优先,大家都很平均

全局队列

Go并发的方法之goroutine模型与调度策略

一个线程如果没有要执行的goroutine,根据work stealing,去别的本地队列偷,如果别的队列也没得偷,就去全局队列里拿,全局队列里别的goroutine前移

到此这篇关于go并发的方法之goroutine模型与调度策略的文章就介绍到这了,更多相关go goroutine模型与调度策略内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://blog.csdn.net/qq_36587495/article/details/121373875

延伸 · 阅读

精彩推荐
  • GolangGo语言实现自动填写古诗词实例代码

    Go语言实现自动填写古诗词实例代码

    这篇文章主要给大家介绍了关于Go语言实现自动填写古诗词的相关资料,这是最近在项目中遇到的一个需求,文中通过示例代码介绍的非常详细,需要的朋...

    FengY5862020-05-14
  • Golang深入浅析Go中三个点(...)用法

    深入浅析Go中三个点(...)用法

    这篇文章主要介绍了深入浅析Go中三个点(...)用法,需要的朋友可以参考下...

    踏雪无痕SS6472021-11-17
  • GolangGolang实现四种负载均衡的算法(随机,轮询等)

    Golang实现四种负载均衡的算法(随机,轮询等)

    本文介绍了示例介绍了Golang 负载均衡的四种实现,主要包括了随机,轮询,加权轮询负载,一致性hash,感兴趣的小伙伴们可以参考一下...

    Gundy_8442021-08-09
  • GolangGO语言字符串处理Strings包的函数使用示例讲解

    GO语言字符串处理Strings包的函数使用示例讲解

    这篇文章主要为大家介绍了GO语言字符串处理Strings包的函数使用示例讲解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步早日升职加...

    Jeff的技术栈6882022-04-14
  • Golanggo语言获取系统盘符的方法

    go语言获取系统盘符的方法

    这篇文章主要介绍了go语言获取系统盘符的方法,涉及Go语言调用winapi获取系统硬件信息的技巧,具有一定参考借鉴价值,需要的朋友可以参考下 ...

    无尽海3862020-04-24
  • GolangGo语言基础单元测试与性能测试示例详解

    Go语言基础单元测试与性能测试示例详解

    这篇文章主要为大家介绍了Go语言基础单元测试与性能测试示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助祝大家多多进步...

    枫少文7812021-12-05
  • GolangGo语言range关键字循环时的坑

    Go语言range关键字循环时的坑

    今天小编就为大家分享一篇关于Go语言range关键字循环时的坑,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来...

    benben_20154202020-05-23
  • GolangGolang 语言极简类型转换库cast的使用详解

    Golang 语言极简类型转换库cast的使用详解

    本文我们通过 cast.ToString() 函数的使用,简单介绍了cast 的使用方法,除此之外,它还支持很多其他类型,在这没有多多介绍,对Golang 类型转换库 cast相关知...

    Golang语言开发栈6112021-12-02