搜索
首页后端开发GolangGo语言并发机制图文详解

Go语言并发机制图文详解

Nov 30, 2019 pm 02:31 PM
go语言

Go 语言相比Java等一个很大的优势就是可以方便地编写并发程序。Go 语言内置了 goroutine 机制,使用goroutine可以快速地开发并发程序, 更好的利用多核处理器资源。这篇文章学习 goroutine 的应用及其调度实现。

 Go语言并发机制图文详解

一、Go语言对并发的支持

使用goroutine编程     (推荐:go视频教程

使用 go 关键字用来创建 goroutine 。将go声明放到一个需调用的函数之前,在相同地址空间调用运行这个函数,这样该函数执行时便会作为一个独立的并发线程。这种线程在Go语言中称作goroutine。

goroutine的用法如下:

//go 关键字放在方法调用前新建一个 goroutine 并执行方法体
go GetThingDone(param1, param2);
 
//新建一个匿名方法并执行
go func(param1, param2) {
}(val1, val2)
 
//直接新建一个 goroutine 并在 goroutine 中执行代码块
go {
    //do someting...
}

因为 goroutine 在多核 cpu 环境下是并行的。如果代码块在多个 goroutine 中执行,我们就实现了代码并行。

如果需要了解程序的执行情况,怎么拿到并行的结果呢?需要配合使用channel进行。

使用Channel控制并发

Channels用来同步并发执行的函数并提供它们某种传值交流的机制。

通过channel传递的元素类型、容器(或缓冲区)和传递的方向由“<-”操作符指定。

可以使用内置函数 make分配一个channel:

i := make(chan int)       // by default the capacity is 0
s := make(chan string, 3) // non-zero capacity
 
r := make(<-chan bool)          // can only read from
w := make(chan<- []os.FileInfo) // can only write to

配置runtime.GOMAXPROCS

使用下面的代码可以显式的设置是否使用多核来执行并发任务:

runtime.GOMAXPROCS()

GOMAXPROCS的数目根据任务量分配就可以,但是不要大于cpu核数。

配置并行执行比较适合适合于CPU密集型、并行度比较高的情景,如果是IO密集型使用多核的化会增加cpu切换带来的性能损失。

了解了Go语言的并发机制,接下来看一下goroutine 机制的具体实现。

二、区别并行与并发

进程、线程与处理器

在现代操作系统中,线程是处理器调度和分配的基本单位,进程则作为资源拥有的基本单位。每个进程是由私有的虚拟地址空间、代码、数据和其它各种系统资源组成。线程是进程内部的一个执行单元。 每一个进程至少有一个主执行线程,它无需由用户去主动创建,是由系统自动创建的。 用户根据需要在应用程序中创建其它线程,多个线程并发地运行于同一个进程中。

并行与并发

并行与并发(Concurrency and Parallelism)是两个不同的概念,理解它们对于理解多线程模型非常重要。

在描述程序的并发或者并行时,应该说明从进程或者线程的角度出发。

并发:一个时间段内有很多的线程或进程在执行,但何时间点上都只有一个在执行,多个线程或进程争抢时间片轮流执行

并行:一个时间段和时间点上都有多个线程或进程在执行

非并发的程序只有一个垂直的控制逻辑,在任何时刻,程序只会处在这个控制逻辑的某个位置,也就是顺序执行。如果一个程序在某一时刻被多个CPU流水线同时进行处理,那么我们就说这个程序是以并行的形式在运行。

并行需要硬件支持,单核处理器只能是并发,多核处理器才能做到并行执行。

并发是并行的必要条件,如果一个程序本身就不是并发的,也就是只有一个逻辑执行顺序,那么我们不可能让其被并行处理。

并发不是并行的充分条件,一个并发的程序,如果只被一个CPU进行处理(通过分时),那么它就不是并行的。

举一个例子,编写一个最简单的顺序结构程序输出"Hello World",它就是非并发的,如果在程序中增加多线程,每个线程打印一个"Hello World",那么这个程序就是并发的。如果运行时只给这个程序分配单个CPU,这个并发程序还不是并行的,需要部署在多核处理器上,才能实现程序的并行。

三、几种不同的多线程模型

用户线程与内核级线程

线程的实现可以分为两类:用户级线程(User-LevelThread, ULT)和内核级线程(Kemel-LevelThread, KLT)。用户线程由用户代码支持,内核线程由操作系统内核支持。

多线程模型

多线程模型即用户级线程和内核级线程的不同连接方式。

(1)多对一模型(M : 1)

将多个用户级线程映射到一个内核级线程,线程管理在用户空间完成。 此模式中,用户级线程对操作系统不可见(即透明)。

1.jpg

优点: 这种模型的好处是线程上下文切换都发生在用户空间,避免的模态切换(mode switch),从而对于性能有积极的影响。

缺点:所有的线程基于一个内核调度实体即内核线程,这意味着只有一个处理器可以被利用,在多处理器环境下这是不能够被接受的,本质上,用户线程只解决了并发问题,但是没有解决并行问题。如果线程因为 I/O 操作陷入了内核态,内核态线程阻塞等待 I/O 数据,则所有的线程都将会被阻塞,用户空间也可以使用非阻塞而 I/O,但是不能避免性能及复杂度问题。

(2) 一对一模型(1:1)

将每个用户级线程映射到一个内核级线程。

2.jpg

每个线程由内核调度器独立的调度,所以如果一个线程阻塞则不影响其他的线程。

优点:在多核处理器的硬件的支持下,内核空间线程模型支持了真正的并行,当一个线程被阻塞后,允许另一个线程继续执行,所以并发能力较强。

缺点:每创建一个用户级线程都需要创建一个内核级线程与其对应,这样创建线程的开销比较大,会影响到应用程序的性能。

(3)多对多模型(M : N)

内核线程和用户线程的数量比为 M : N,内核用户空间综合了前两种的优点。 

3.jpg

这种模型需要内核线程调度器和用户空间线程调度器相互操作,本质上是多个线程被绑定到了多个内核线程上,这使得大部分的线程上下文切换都发生在用户空间,而多个内核线程又可以充分利用处理器资源。

四、goroutine机制的调度实现

goroutine机制实现了M : N的线程模型,goroutine机制是协程(coroutine)的一种实现,golang内置的调度器,可以让多核CPU中每个CPU执行一个协程。

理解goroutine机制的原理,关键是理解Go语言scheduler的实现。

调度器是如何工作的

Go语言中支撑整个scheduler实现的主要有4个重要结构,分别是M、G、P、Sched, 前三个定义在runtime.h中,Sched定义在proc.c中。

Sched结构就是调度器,它维护有存储M和G的队列以及调度器的一些状态信息等。

M结构是Machine,系统线程,它由操作系统管理的,goroutine就是跑在M之上的;M是一个很大的结构,里面维护小对象内存cache(mcache)、当前执行的goroutine、随机数发生器等等非常多的信息。

P结构是Processor,处理器,它的主要用途就是用来执行goroutine的,它维护了一个goroutine队列,即runqueue。Processor是让我们从N:1调度到M:N调度的重要部分。

G是goroutine实现的核心结构,它包含了栈,指令指针,以及其他对调度goroutine很重要的信息,例如其阻塞的channel。

Processor的数量是在启动时被设置为环境变量GOMAXPROCS的值,或者通过运行时调用函数GOMAXPROCS()进行设置。Processor数量固定意味着任意时刻只有GOMAXPROCS个线程在运行go代码。

我们分别用三角形,矩形和圆形表示Machine Processor和Goroutine。

4.jpg

在单核处理器的场景下,所有goroutine运行在同一个M系统线程中,每一个M系统线程维护一个Processor,任何时刻,一个Processor中只有一个goroutine,其他goroutine在runqueue中等待。一个goroutine运行完自己的时间片后,让出上下文,回到runqueue中。 多核处理器的场景下,为了运行goroutines,每个M系统线程会持有一个Processor。

5.jpg

在正常情况下,scheduler会按照上面的流程进行调度,但是线程会发生阻塞等情况,看一下goroutine对线程阻塞等的处理。

线程阻塞

当正在运行的goroutine阻塞的时候,例如进行系统调用,会再创建一个系统线程(M1),当前的M线程放弃了它的Processor,P转到新的线程中去运行。

6.JPG

runqueue执行完成

当其中一个Processor的runqueue为空,没有goroutine可以调度。它会从另外一个上下文偷取一半的goroutine。

7.jpg

五、对并发实现的进一步思考

Go语言的并发机制还有很多值得探讨的,比如Go语言和Scala并发实现的不同,Golang CSP 和Actor模型的对比等。

了解并发机制的这些实现,可以帮助我们更好的进行并发程序的开发,实现性能的最优化。

关于三种多线程模型,可以关注一下Java语言的实现。

我们知道Java通过JVM封装了底层操作系统的差异,而不同的操作系统可能使用不同的线程模型,例如Linux和windows可能使用了一对一模型,solaris和unix某些版本可能使用多对多模型。JVM规范里没有规定多线程模型的具体实现,1:1(内核线程)、N:1(用户态线程)、M:N(混合)模型的任何一种都可以。谈到Java语言的多线程模型,需要针对具体JVM实现,比如Oracle/Sun的HotSpot VM,默认使用1:1线程模型。

以上是Go语言并发机制图文详解的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文转载于:博客园。如有侵权,请联系admin@php.cn删除
Golang vs. Python:并发和多线程Golang vs. Python:并发和多线程Apr 17, 2025 am 12:20 AM

Golang更适合高并发任务,而Python在灵活性上更有优势。1.Golang通过goroutine和channel高效处理并发。2.Python依赖threading和asyncio,受GIL影响,但提供多种并发方式。选择应基于具体需求。

Golang和C:性能的权衡Golang和C:性能的权衡Apr 17, 2025 am 12:18 AM

Golang和C 在性能上的差异主要体现在内存管理、编译优化和运行时效率等方面。1)Golang的垃圾回收机制方便但可能影响性能,2)C 的手动内存管理和编译器优化在递归计算中表现更为高效。

Golang vs. Python:申请和用例Golang vs. Python:申请和用例Apr 17, 2025 am 12:17 AM

selectgolangforhighpperformanceandcorrency,ifealforBackendServicesSandNetwork程序; selectpypypythonforrapiddevelopment,dataScience和machinelearningDuetoitsverserverserverserversator versator anderticality andextility andextentensivelibraries。

Golang vs. Python:主要差异和相似之处Golang vs. Python:主要差异和相似之处Apr 17, 2025 am 12:15 AM

Golang和Python各有优势:Golang适合高性能和并发编程,Python适用于数据科学和Web开发。 Golang以其并发模型和高效性能着称,Python则以简洁语法和丰富库生态系统着称。

Golang vs. Python:易于使用和学习曲线Golang vs. Python:易于使用和学习曲线Apr 17, 2025 am 12:12 AM

Golang和Python分别在哪些方面更易用和学习曲线更平缓?Golang更适合高并发和高性能需求,学习曲线对有C语言背景的开发者较平缓。Python更适合数据科学和快速原型设计,学习曲线对初学者非常平缓。

表演竞赛:Golang vs.C表演竞赛:Golang vs.CApr 16, 2025 am 12:07 AM

Golang和C 在性能竞赛中的表现各有优势:1)Golang适合高并发和快速开发,2)C 提供更高性能和细粒度控制。选择应基于项目需求和团队技术栈。

Golang vs.C:代码示例和绩效分析Golang vs.C:代码示例和绩效分析Apr 15, 2025 am 12:03 AM

Golang适合快速开发和并发编程,而C 更适合需要极致性能和底层控制的项目。1)Golang的并发模型通过goroutine和channel简化并发编程。2)C 的模板编程提供泛型代码和性能优化。3)Golang的垃圾回收方便但可能影响性能,C 的内存管理复杂但控制精细。

Golang的影响:速度,效率和简单性Golang的影响:速度,效率和简单性Apr 14, 2025 am 12:11 AM

GoimpactsdevelopmentPositationalityThroughSpeed,效率和模拟性。1)速度:gocompilesquicklyandrunseff,ifealforlargeprojects.2)效率:效率:ITScomprehenSevestAndArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdArdEcceSteral Depentencies,增强开发的简单性:3)SimpleflovelmentIcties:3)简单性。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
1 个月前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
1 个月前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
1 个月前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.聊天命令以及如何使用它们
1 个月前By尊渡假赌尊渡假赌尊渡假赌

热工具

适用于 Eclipse 的 SAP NetWeaver 服务器适配器

适用于 Eclipse 的 SAP NetWeaver 服务器适配器

将Eclipse与SAP NetWeaver应用服务器集成。

安全考试浏览器

安全考试浏览器

Safe Exam Browser是一个安全的浏览器环境,用于安全地进行在线考试。该软件将任何计算机变成一个安全的工作站。它控制对任何实用工具的访问,并防止学生使用未经授权的资源。

Atom编辑器mac版下载

Atom编辑器mac版下载

最流行的的开源编辑器

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

Dreamweaver Mac版

Dreamweaver Mac版

视觉化网页开发工具