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

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

服务器之家 - 脚本之家 - Golang - Go语言中并发的工作原理

Go语言中并发的工作原理

2022-07-16 14:00奋斗的大橙子 Golang

本文详细讲解了Go语言中并发的工作原理,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

一、Go语言中Goroutine的基本原理

Go语言里的并发指的是能让某个函数独立于其他函数运行的能力。

Go语言的goroutine是一个独立的工作单元,

Go 语言的并发同步模型来自一个叫作通信顺序进程(Communicating Sequential Processes,CSP)的范型(paradigm)。

CSP 是一种消息传递模型,通过在goroutine 之间传递数据来传递消息,而不是对数据进行加锁来实现同步访问。消息的传递通过Go语言中的Channel(通道)来实现。

进程(process) 看作一个包含了应用程序在运行中需要用到和维护的各种资源的容器。

线程(Thread)是一个执行空间,这个空间会被操作系统调度来运行函数中所写的代码。

每个进程至少包含一个线程,每个进程的初始线程被称作主线程。因为执行这个线程的空间是应用程序的本身的空间,所以当主线程终止时,应用程序也会终止。

下图就是进程和线程的简要关系。

Go语言中并发的工作原理

补充:句柄是什么?

我的理解句柄就是给用户操作内核资源的指针,指向指针的指针。【把手】和【门】的关系,使用们把手能转动整个门(系统资源)

操作系统会在物理处理器上调度线程来运行,而Go 语言的运行时会在逻辑处理器上调度goroutine来运行。每个逻辑处理器都分别绑定到单个操作系统线程。下面我们就来简单描述一下goroutine执行的流程。

首先来了解一下操作系统线程、逻辑处理器和本地运行队列

全局运行队列:刚创建的goruntine会被安排到这里面,通过一些调度算法,分配给逻辑处理器

操作系统线程:这个就是传统意义上的线程,用于具体goroutine的执行,他会和一个逻辑器进行绑定

逻辑处理器:里面维护着一个本地的队列,用于本地队列里面goroutine的调度

本地运行队列:装载着待执行的goruntine

支撑整个调度器的主要有4个重要结构,分别是M、G、P、Sched,前三个定义在runtime.h中,Sched定义在proc.c中。

  • Sched结构就是调度器,它维护有存储M和G的队列以及调度器的一些状态信息等。
  • M代表内核级线程,一个M就是一个线程,goroutine就是跑在M之上的;M是一个很大的结构,里面维护小对象内存cache(mcache)、当前执行的goroutine、随机数发生器等等非常多的信息。
  • P全称是Processor,处理器,它的主要用途就是用来执行goroutine的,所以它也维护了一个goroutine队列,里面存储了所有需要它来执行的goroutine,这个P的角色可能有一点让人迷惑,一开始容易和M冲突,后面重点聊一下它们的关系。
  • G就是goroutine实现的核心结构了,G维护了goroutine需要的栈、程序计数器以及它所在的M等信息。

Go语言中并发的工作原理

整个过程描述:

当创建一个Goroutine的时候,先放到全局队列当中,然后会把这个Goroutine分配到一个逻辑处理器的本地队列中,这个逻辑处理器会绑定一个操作系统线程,由这个线程去执行Goroutine的代码。

生动描述:

地鼠(gopher)用小车运着一堆待加工的砖。M就可以看作图中的地鼠,P就是小车,G就是小车里装的砖。一图胜千言啊,弄清楚了它们三者的关系,下面我们就开始重点聊地鼠是如何在搬运砖块的。

Go语言中并发的工作原理

1.runqget, 地鼠(M)试图从自己的小车(P)取出一块砖(G),当然结果可能失败,也就是这个地鼠的小车已经空了,没有砖了。

2.findrunnable, 如果地鼠自己的小车中没有砖,那也不能闲着不干活是吧,所以地鼠就会试图跑去工场仓库取一块砖来处理;工场仓库也可能没砖啊,出现这种情况的时候,这个地鼠也没有偷懒停下干活,而是悄悄跑出去,随机盯上一个小伙伴(地鼠),然后从它的车里试图偷一半砖到自己车里。如果多次尝试偷砖都失败了,那说明实在没有砖可搬了,这个时候地鼠就会把小车还回停车场,然后睡觉休息了。如果地鼠睡觉了,下面的过程当然都停止了,地鼠睡觉也就是线程sleep了。

3.wakep, 到这个过程的时候,可怜的地鼠发现自己小车里有好多砖啊,自己根本处理不过来;再回头一看停车场居然有闲置的小车,立马跑到宿舍一看,你妹,居然还有小伙伴在睡觉,直接给屁股一脚,“你妹,居然还在睡觉,老子都快累死了,赶紧起来干活,分担点工作。”,小伙伴醒了,拿上自己的小车,乖乖干活去了。有时候,可怜的地鼠跑到宿舍却发现没有在睡觉的小伙伴,于是会很失望,最后只好向工场老板说——”停车场还有闲置的车啊,我快干不动了,赶紧从别的工场借个地鼠来帮忙吧。”,最后工场老板就搞来一个新的地鼠干活了。

4.execute,地鼠拿着砖放入火种欢快的烧练起来。

注: “地鼠偷砖”叫work stealing,一种调度算法。

到这里,貌似整个工场都正常的运转起来了,无懈可击的样子。不对,还有一个疑点没解决啊,假设地鼠的车里有很多砖,它把一块砖放入火炉中后,何时把它取出来,放入第二块砖呢?难道要一直把第一块砖烧练好,才取出来吗?那估计后面的砖真的是等得花儿都要谢了。这里就是要真正解决goroutine的调度,上下文切换问题。

goroutine的阻塞

当一个OS线程M0陷入阻塞时(如下图),P转而在运行M1,图中的M1可能是正被创建,或者从线程缓存中取出。

Go语言中并发的工作原理

简单解释就是,当当前的Goroutine在阻塞,就把他和当前线程绑定,让当前的线程继续执行这个Goroutine(就是等待),其他的goroutine随着逻辑处理器被绑定到另一个线程上,继续执行。

当阻塞的线程返回时,它必须尝试取得一个逻辑处理器来运行goroutine,一般情况下,它会从其他的OS线程那里拿一个P过来,如果没有拿到的话,它就把goroutine放在一个全局运行队列里,然后自己睡眠(放入线程缓存里)。所有的P也会周期性的检查global runqueue并运行其中的goroutine,否则global runqueue上的goroutine永远无法执行。

还有就像下面的图片,左边的线程一个满载状态,一个没有goroutine,此时的做法就是会进行重新分配,就想右侧图展示

Go语言中并发的工作原理

参考 :https://morsmachine.dk/go-scheduler

二、Go语言中的并发和并行

并发是两个任务可以在重叠的时间段内启动,运行和完成。并行是任务在同一时间运行,例如,在多核处理器上。

并发是独立执行过程的组合,而并行是同时执行(可能相关的)计算。

并发是一次处理很多事情,并行是同时做很多事情。

  • 应用程序可以是并发的,但不是并行的,这意味着它可以同时处理多个任务,但是没有两个任务在同一时刻执行。
  • 应用程序可以是并行的,但不是并发的,这意味着它同时处理多核CPU中的任务的多个子任务。
  • 应用程序可以即不是并行的,也不是并发的,这意味着它一次一个地处理所有任务。
  • 应用程序可以即是并行的也是并发的,这意味着它同时在多核CPU中同时处理多个任务。

简单讲:并行就是同时做很多事 并发就是一堆事情一个时间点来了,然后通过分片等方式感觉像都在执行

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对服务器之家的支持。如果你想了解更多相关内容请查看下面相关链接

原文地址:https://www.cnblogs.com/dcz2015/p/10106866.html

延伸 · 阅读

精彩推荐
  • GolangGolang 如何解析和生成json

    Golang 如何解析和生成json

    这篇文章主要介绍了Golang 如何解析和生成json,帮助大家更好的理解和学习golang,感兴趣的朋友可以了解下 ...

    Dabelv5262020-09-05
  • Golang详解Golang语言中的interface

    详解Golang语言中的interface

    这篇文章主要介绍了Golang语言中的interface的相关资料,帮助大家更好的理解和使用golang,感兴趣的朋友可以了解下...

    雨燕3792021-03-24
  • Golang使用 go 实现多线程下载器的方法

    使用 go 实现多线程下载器的方法

    本篇文章带领大家学习使用go实现一个简单的多线程下载器,给她家详细介绍了多线程下载原理及实例代码,感兴趣的朋友跟随小编一起看看吧...

    qxcheng10422021-11-18
  • Golang关于Golang中range指针数据的坑详解

    关于Golang中range指针数据的坑详解

    这篇文章主要给大家介绍了关于Golang中range指针数据的坑的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值...

    脚本之家3282020-05-22
  • Golanggolang语言中for循环语句用法实例

    golang语言中for循环语句用法实例

    这篇文章主要介绍了golang语言中for循环语句用法,实例分析了for循环遍历的使用技巧,具有一定参考借鉴价值,需要的朋友可以参考下 ...

    shichen20146932020-04-12
  • GolangGo语言Web编程实现Get和Post请求发送与解析的方法详解

    Go语言Web编程实现Get和Post请求发送与解析的方法详解

    这篇文章主要介绍了Go语言Web编程实现Get和Post请求发送与解析的方法,结合实例形式分析了Go语言客户端、服务器端结合实现web数据get、post发送与接收数据的...

    typ20044102020-05-06
  • Golanggolang日志包logger的用法详解

    golang日志包logger的用法详解

    这篇文章主要介绍了golang日志包logger的用法详解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    老衲一头头秀发5232021-06-18
  • GolangGo并发控制WaitGroup的使用场景分析

    Go并发控制WaitGroup的使用场景分析

    WaitGroup,可理解为Wait-Goroutine-Group,即等待一组goroutine结束,本文通过具体场景结合实际例子给大家介绍使用WaitGroup控制的实现方法,感兴趣的朋友跟随小...

    failymao6682021-08-15