Go学习笔记—Go并发基础

Go学习笔记—Go并发基础,第1张

Go学习笔记—Go并发基础 Go并发基础

并行:程序在任意时刻内都是同时运行
并发:程序在单位时间内都是同时运行的
​扇入:多条通道聚合到一条通道中(select聚合,加密解密服务)
​扇出:一条通道发散到多条通道中(goroutine实现并发,Web服务器并发处理用户请求)

​ 在java/c++中我们要实现并发编程的时候,我们通常需要自己维护一个线程池,并且需要自己去包装一个又一个的任务,同时需要自己去调度线程执行任务并维护上下文切换。

​ Go语言中的goroutine就是这样一种机制,goroutine的概念类似于线程,但 goroutine是由Go的运行时(runtime)调度和管理的。Go程序会智能地将 goroutine 中的任务合理地分配给每个CPU。Go语言之所以被称为现代化的编程语言,就是因为它在语言层面已经内置了调度和上下文切换的机制。

(1)goroutine可以在用户空间调度,避免内核态和用户态的切换。

(2)goroutine是语言原生支持的,屏蔽了大部分复杂底层实现。

(3)goroutine更小的栈空间允许用户创建更多的实例。

Go语言并行调度原理

GPM是Go语言运行时(runtime)层面实现,是go语言自己实现的一套调度系统。区别于 *** 作系统调度OS线程。

  • G就是goroutine,它不是一个运行实体,而是用于存放并发执行的代码入口地址,上下文,运行环境(关联的P和M),运行栈等元信息。为了减少对象的分配和回收,G对象可以被复用(执行完的goroutine可以重新初始化)。

  • P(Processor)管理着一组goroutine队列,P是存储当前goroutine运行的上下文环境(函数指针,堆栈地址及地址边界)的一个数据结构而非控制实体,P会对自己管理的goroutine队列做一些调度(比如把占用CPU时间较长的goroutine暂停、运行后续的goroutine等等)当自己的队列消费完了就去全局队列里取,如果全局队列里也消费完了会去其他P的队列里抢任务。

  • M(machine)是Go运行时(runtime)对 *** 作系统内核线程的虚拟,是 *** 作系统层面调度和运行的实体。 M与内核线程一般是一一映射的关系, 一个groutine最终是要放到M上执行的,M仅负责执行,资源来自于P和G;P与M一般也是一一对应的。他们关系是: P管理着一组G挂载在M上运行。当一个G长久阻塞在一个M上时,runtime会新建一个M,绑定相应的P,阻塞G所在的P会把其他的G 挂载在新建的M上。当旧的G阻塞完成或者认为其已经死掉时 回收旧的M。

  • M拥有自己的栈g0,但只有当拿到P才可以执行,M会在堆栈g0上恢复G的上下文,完成后切换到G的栈开始执行

Go启动初始化过程:

  1. 分配和检查栈空间。
  2. 初始化参数和环境变量。
  3. 当前运行线程标记为m0,即程序主线程。
  4. 调用运行时初始化函数runtime.schedinit 进行初始化。(内存空间分配,GC,生成空闲P列表)
  5. 在m0上调度第一个G,这个G负责运行runtime.main函数。runtime.main会拉起运行时的监控线程(对应一个M,专门监控、控制程序的内存和调度信息),然后调用main包的init()初始化函数,最后执行main函数。

总结:

  1. 一个 *** 作系统线程对应用户态多个goroutine。
  2. go程序可以同时使用多个 *** 作系统线程。
  3. goroutine和OS线程是多对多的关系,即m:n。
命令作用runtime.GOMAXPROCS(x)x==0时为查询可以并发执行的goroutine数目 ;x>0时为设置GOMAXPROCS值runtime.Goexit结束当前goroutine运行(会调用其defer但是不会产生panic)runtime.Gosched放弃当前调度执行的机会,将当前goroutine放到Processor的队尾runtime.NumGoroutine返回当前程序的goroutine个数

Go语言为什么并行更快?

​ Go语言相比起其他语言的优势在于OS线程是由OS内核来调度的,goroutine则是由Go运行时(runtime)自己的调度器调度的,这个调度器使用一个称为m:n调度的技术(复用/调度m个goroutine到n个OS线程)。 goroutine的调度是在用户态下完成的, 不涉及内核态与用户态之间的频繁切换,包括内存的分配与释放,都是在用户态维护着一块大的内存池, 不直接调用系统的malloc函数(除非内存池需要改变),成本比调度OS线程低很多。 另一方面充分利用了多核的硬件资源,近似的把若干goroutine均分在物理线程上, 再加上本身goroutine的超轻量,以上种种保证了go调度方面的性能。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5638321.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-16
下一篇 2022-12-16

发表评论

登录后才能评论

评论列表(0条)

保存