九、Golang并发和线程模型
@Author:Runsen
开始前来介绍几个概念:
- 进程:进程是程序在操作系统中的一次执行过程,系统进行资源分配和调度的一个独立单位。
- 线程:线程是进程的一个执行实体,是 CPU 调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。
- 并发:多线程程序在单核心的 cpu 上运行,称为并发
- 并行:多线程程序在多核心的 cpu 上运行,称为并行。
- 协程:独立的栈空间,共享堆空间,调度由用户自己控制,本质上有点类似于用户级线程,一个线程上可以跑多个协程,协程是轻量级的线程。
并发与并行并不相同,并发主要由切换时间片来实现“同时”运行,并行则是直接利用多核实现多线程的运行,Go程序可以设置使用核心数,以发挥多核计算机的能力。
线程主要分为用户线程和内核线程,用户线程由各语言代码所支持,而内核线程是由操作系统内核所支持。多线程模型主要就是用户线程与内核线程的连接方式:
下面我们来探讨Go的线程模型,首先我们先来回顾下常见的三种线程模型,然后在介绍Go中独特的线程模型CSP。
文章目录
- 三种线程模型
- Goroutine
- CSP
三种线程模型
线程模型主要有三种:1、内核级别线程;2、用户级别线程;3、混合线程,分别对应的是1:1、N:1、M:N。
内核级别线程:一对一模型(1 : 1):每个用户级线程映射到一个内核级线程。优点是缓存读写快速,缺点是容易阻塞。
用户级别线程: 多对一模型(M : 1):多个用户级线程映射到一个内核级线程,线程管理在用户空间完成。
混合线程:多对多模型(M : N):内核线程和用户线程的数量比为 M : N,综合了前两种的优点
Goroutine
goroutine 是 Go 语言并行设计的核心,有人称之为 go 程。goroutine 是轻量级线程,goroutine 的调度是由 Golang 运行时进行管理的。在Java中,goroutine就是Thead 。
goroutine 语法格式:go 函数名( 参数列表 )
。例如:go f(x, y, z)
,开启一个新的 goroutine:f(x, y, z)
。
在并发编程中,我们通常想将一个过程切分成几块,然后让每个 goroutine 各自负责一块工作,当一个程序启动时,主函数在一个单独的 goroutine 中运行,我们叫它 `main goroutine。新的 goroutine 会用 go 语句来创建。而 go 语言的并发设计,让我们很轻松就可以达成这一目的。
我们来看一个示例。
package mainimport ("fmt""time"
)func newTask() {i := 0for {i++fmt.Printf("new goroutine: i = %d\n", i)time.Sleep(1*time.Second) //延时1s}
}func main() {//创建一个 goroutine,启动另外一个任务go newTask()i := 0//main goroutine 循环打印 不会暂停for {i++fmt.Printf("main goroutine: i = %d\n", i)time.Sleep(1 * time.Second) //延时1s}
}
程序运行结果:
如果主 goroutine 退出后,那么其它的工作 goroutine 也会自动退出:
package mainimport (
"fmt"
"time"
)func newTask() {i := 0for {i++fmt.Printf("new goroutine: i = %d\n", i)time.Sleep(1 * time.Second) //延时1s}
}func main() {//创建一个 goroutine,启动另外一个任务go newTask()fmt.Println("main goroutine exit")
}
程序运行结果如下,不会一直执行。
new goroutine: i = 1
main goroutine exit
上面就是Go实现了并发比较常见的Goroutine方法。
CSP
我们常见的多线程模型一般是通过共享内存实现的(就是Goroutine的原理),但是共享内存就会有很多问题。比如资源抢占的问题、一致性问题等等。为了解决这些问题,我们需要引入多线程锁、原子操作等等限制来保证程序执行结果的正确性。
这就引出了另外一种是Go语言特有的并发形式,也是Go语言推荐的:CSP(communicating sequential processes)并发模型。
Go的CSP并发模型,是通过goroutine和channel来实现的。
CSP模式中,消息是通过Channel来通讯的,Channel相当于一个消息通讯的中间人,这样可以让两个通讯实体的耦合更松一些
下面Runsen先介绍下Channel,回顾一下基础知识。通道可用于两个 goroutine 之间通过传递一个指定类型的值来同步运行和通讯。操作符 <-
用于指定通道的方向,发送或接收。如果未指定方向,则为双向通道。
ch <- v // 把 v 发送到通道 ch
v := <-ch // 从 ch 接收数据// 并把值赋给 v
声明一个通道很简单,我们使用chan关键字即可,通道在使用前必须先创建:
ch := make(chan int)
channel分为两种,有缓冲channel和无缓冲channel,默认情况下,通道是不带缓冲区的。我们通过下边的代码例子来区分不同的channel种类。
package mainimport ("fmt"
)func main() {pipline := make(chan string) //构造无缓冲通道pipline <- "hello world" //发送数据fmt.Println(<-pipline) //读数据
}
运行会抛出错误,如下:
fatal error: all goroutines are asleep - deadlock!
如果把这个例子改成有缓冲通道还会阻塞吗?我们继续看下边的例子:
package mainimport ("fmt"
)func main() {pipline := make(chan string, 1 ) //构造无缓冲通道pipline <- "hello world" //发送数据fmt.Println(<-pipline) //读数据
}hello world
这里运行正常,此时就说明了缓冲和没有缓冲的区别在于在发送操作是否发生在有接受者时。那么,对于有缓冲通道会发生什么特殊情况呢?
如果这段代码,通道容量为 1,但是往通道中写入两条数据,对于一个协程来说就会造成死锁。
package mainimport ("fmt"
)
func main() {ch1 := make(chan string, 1)ch1 <- "hello world"ch1 <- "hello China"fmt.Println(<-ch1)
}//fatal error: all goroutines are asleep - deadlock!
每个缓冲通道,都有容量,当通道里的数据量等于通道的容量后,此时再往通道里发送数据,就失造成阻塞,必须等到有人从通道中消费数据后,程序才会往下进行。
下面,我们看goroutine和channel实现CSP并发模型,代码来自菜鸟教程。
package mainimport "fmt"
// 计算数字之和
func sum(s []int, c chan int) {sum := 0for _, v := range s {sum += v}c <- sum // 把 sum 发送到通道 c
}func main() {s := []int{7, 2, 8, -9, 4, 0}c := make(chan int)go sum(s[:len(s)/2], c) //-9+4+0go sum(s[len(s)/2:], c) // 7+2+8x, y := <-c, <-c // 从通道 c 中接收fmt.Println(x, y, x+y) //-5 17 12\
}
上面示例通过两个 goroutine 来计算数字之和,在 goroutine 完成计算后,它会计算两个结果的和。这里的channel是没有缓冲。
通道可以设置缓冲区,通过 make 的第二个参数指定缓冲区大小。
package mainimport "fmt"func sum(s []int, c chan int) {sum := 0for _, v := range s {sum += v}c <- sum // 把 sum 发送到通道 c
}func main() {// 这里我们定义了一个可以存储整数类型的带缓冲通道// 缓冲区大小为2,因为存储了一个数字,所以没有报错s := []int{7, 2, 8, -9, 4, 0}c := make(chan int ,2)go sum(s[:len(s)/2], c)go sum(s[len(s)/2:], c)x, y := <-c, <-c // 从通道 c 中接收fmt.Println(x, y, x+y) // -5 17 12
}
九、Golang并发和线程模型相关推荐
- 地鼠宝宝的轶事奇闻之线程模型
Golang并发机制 线程模型 在操作系统提供的内核线程之上,go搭建了一个两级线程模型.毫无疑问,其中一级必然是内核线程,另一级便是goroutine.你可以将goroutine看作是应用程序线程. ...
- Go 语言编程 — 并发 — GMP 调度模型
目录 文章目录 目录 并发和并行 如何交互?CSP 通信模型 如何调度?GMP 调度模型 用户级线程模型(多对一) 内核级线程模型(一对一) 两级线程模型(多对多) GMP 线程模型 Go Runti ...
- Golang并发模型:轻松入门协程池
goroutine是非常轻量的,不会暂用太多资源,基本上有多少任务,我们可以开多少goroutine去处理.但有时候,我们还是想控制一下. 比如,我们有A.B两类工作,不想把太多资源花费在B类务上,而 ...
- Golang并发模型:合理退出并发协程
goroutine作为Golang并发的核心,我们不仅要关注它们的创建和管理,当然还要关注如何合理的退出这些协程,不(合理)退出不然可能会造成阻塞.panic.程序行为异常.数据结果不正确等问题.这篇 ...
- Golang面向并发的内存模型
Golang面向并发的内存模型 在早期,CPU都是以单核的形式顺序执行机器指令.Go语言的祖先C语言正是这种顺序编程语言的代表.顺序编程语言中的顺序是指:所有的指令都是以串行的方式执行,在相同的时刻有 ...
- Golang并发编程-GPM协程调度模型原理及组成分析
文章目录 一.操作系统的进程和线程模型 1.1.基础知识 1.2.KST/ULT 二.Golang的GPM协程调度模型 三.M的结构及对应关系 四.P的结构及状态转换 五.G的结构及状态转换 六.GP ...
- mongodb线程池_常用高并发网络线程模型设计及MongoDB线程模型优化实践
服务端通常需要支持高并发业务访问,如何设计优秀的服务端网络IO工作线程/进程模型对业务的高并发访问需求起着至关重要的核心作用. 本文总结了了不同场景下的多种网络IO线程/进程模型,并给出了各种模型的优 ...
- C#高性能大容量SOCKET并发(十):SocketAsyncEventArgs线程模型
原文:C#高性能大容量SOCKET并发(十):SocketAsyncEventArgs线程模型 线程模型 SocketAsyncEventArgs编程模式不支持设置同时工作线程个数,使用的NET的IO ...
- redis 的线程模型是什么?为什么 redis 单线程却能支撑高并发?
redis 的线程模型 redis 内部使用文件事件处理器 file event handler,这个文件事件处理器是单线程的,所以 redis 才叫做单线程的模型.它采用 IO 多路复用机制同时监听 ...
最新文章
- 局域网通讯工具_自动称重带无线通讯WIFI传输功能设备
- htmlparser解析网站时服务器返回的文件编码和页面编码不一致问题
- linux 之RAID详解
- php读取移动硬盘数据,移动硬盘打不开,数据怎么恢复?
- CSS clear 清除浮动,兼容各浏览器
- PHP图形图像的典型应用 --常用图像的应用(验证码)
- mac mysql5.7.10 密码_MAC下Mysql5.7.10版本修改root密码的方法
- 想学数据分析(人工智能)需要学哪些课程?
- 《众妙之门——用户体验设计的秘密》一2.3 触摸至上的设计
- linux-推荐两款好用的录屏软件
- 自动售货机软件工程课设_饮料自动售货机系统实验.docx
- 自然语言处理中的预训练模型-邱锡鹏老师
- node.js 安装详细步骤教程
- deepfacelab安卓版_deepfacelab
- funcode之c++版弹弹堂(第一个设计实验)
- tensorflow常用数据函数总结(tf.tile()、tf.expand_dims())
- SHOUG线上活动 Maclean Liu分享《学习甲骨文数据库的自由之翼-与Oracle的世界相连接》...
- 华为鸿蒙源自那句话,华为鸿蒙系统名字源自山海经它的很多自主专利都源于这本古籍,为什么?...
- 最大流与最小割(Maxflow与Mincut)
- win7和linux下的文件共享
热门文章
- libwebsockets / vs2019 编译 libwebsockets 4.0 方法
- 乐鑫代理启明云端分享|基于ESP32-S2彩色触摸屏86面板方案
- 高德地图android4,Android高德之旅(4)我的位置
- vue 多个filters_vue自定义filters过滤器
- 基于MIG控制器的DDR3读写控制详解
- android硬编码封装mp4,【Android 音视频开发打怪升级:音视频硬解码篇】四、音视频解封和封装:生成一个MP4...
- Singleton模式(单例模式) 饿汉式和懒汉式
- 归属地的判断规则有吗_IPO|创业板注册制规则-详解股权激励新规
- 脑子笨的人可以学计算机吗,脑子笨的人有什么特征 反应慢的人其实很聪明
- NLP word2vec 计算优化