go语言并发编程
引言
说到go语言最厉害的是什么就不得不提到并发,并发是什么?,与并发相关的并行又是什么?
并发:同一时间段内执行多个任务
并行:同一时刻执行多个任务

进程、线程与协程
- 进程:
进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。每个进程都有自己的独立内存空间,不同进程通过进程间通信来通信。由于进程比较重量,占据独立的内存,所以上下文进程间的切换开销(栈、寄存器、虚拟内存、文件句柄等)比较大,但相对比较稳定安全。 - 线程:
线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。线程间通信主要通过共享内存,上下文切换很快,资源开销较少,但相比进程不够稳定容易丢失数据。 - 协程:
协程是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。
goroutine
go语言原生支持并发,可以用go关键字快速的让一个函数创建为goroutine协程,也可以创建多个goroutine去执行相同的函数。
sync.WaitGroup可以用来实现goroutine的同步
例如:
var wg sync.WaitGroup
func hello(i int) {
defer wg.Done() // goroutine结束就-1
fmt.Println("Hello Goroutine!", i)
}
func main() {
for i := 0; i < 10; i++ {
wg.Add(1) // 启动一个goroutine就+1
go hello(i)
}
wg.Wait() // 等待所有登记的goroutine都结束
}
最终打印出来的顺序是乱序,因为goroutine是并发操作。
goroutine实际上就是go中的协程,在go语言中可以起成千上万个goroutine协程来进行并发编程
goroutine的调度
goroutine的调度基于GMP模型
- G代表一个goroutine对象,每次go调用的时候,都会创建一个G对象
- M代表一个线程,每次创建一个M的时候,都会有一个底层线程创建;所有的G任务,最终还是在M上执行
- P代表一个处理器,每一个运行的M都必须绑定一个P,就像线程必须在么一个CPU核上执行一样

P的个数就是GOMAXPROCS(最大256),启动时固定的,一般不修改; M的个数和P的个数不一定一样多(会有休眠的M或者不需要太多的M)(最大10000);每一个P保存着本地G任务队列,也有一个全局G任务队列;
并发安全
go原生提供并发原语goroutine和channel为构造并发提供了一种优雅而简单的方式,go没有显示的利用锁来控制并发安全,而是鼓励提倡通过通信共享内存而不是通过共享内存而实现通信。
sync.atomic
Go语言中原子操作由内置的标准库sync/atomic提供。
这些功能需要非常小心才能正确使用。 除特殊的底层应用程序外,同步更适合使用channel或sync包的功能。 通过消息共享内存; 不要通过共享内存进行通信。

Mutex
互斥锁是一种常用的共享资源访问的方法,它能够保证同时只有一个goroutine可以访问资源。Go语言中使用sync包的Mutex类型来实现互斥锁。

go在1.8默认使用自旋模式,当试图获取已经被持有的锁时,如果本地队列为空并且 P 的数量大于1,goroutine 将自旋几次(用一个 P 旋转会阻塞程序)。自旋后,goroutine park。在程序高频使用锁的情况下,它充当了一个快速路径。
go在1.9新增了Starving模式,当自旋模式抢到锁,表示有协程释放了锁,如果waiter>0,即有阻塞等待的协程,会释放信号量来唤醒协程,当协程被唤醒后,发现Locked=1,锁又被抢占,则又会阻塞,但在阻塞前会判断自上次阻塞到本次阻塞经历了多长时间,如果超过1ms的话,会将Mutex标记为"饥饿"模式,然后再阻塞。当被标记为饥饿状态时,unlock 方法会 handsoff 把锁直接扔给第一个等待者。
在饥饿模式下,自旋也被停用,因为传入的goroutines 将没有机会获取为下一个等待者保留的锁。

RWMutex
互斥锁是完全互斥的,但是有很多场景下读多写少,因此我们并发去读取一个资源而不涉及到资源修改的时候是完全没必要加锁的,这种情况下读写锁是一种更好的选择。
读写锁分为读锁和写锁,读锁与读锁兼容,读锁与写锁互斥,写锁与写锁互斥。
errgroup
ErrGroup是 Go 官方提供的一个同步扩展库。可以将一个大任务拆分成几个小任务并发执行,提高程序效率。sync.ErrGroup在sync.WaitGroup功能的基础上,增加了错误传递,以及在发生不可恢复的错误时取消整个goroutine集合,或者等待超时
sync.pool
go语言为了降低GC压力引入了sync.Pool对象池用来保存和复用临时对象。sync.Pool是可伸缩的,并发安全的。其大小仅受限于内存的大小。sync.pool对象池比较适合用来存储一些临时切状态无关的数据,但是不适合用来做连接池,因为存入对象池中的值有可能会在垃圾回收时被删除掉
在go的1.13版本中引入了victim cache,会将pool内数据拷贝一份,避免GC将其清空,即使没有引用的内容也可以保留最多两轮GC.
channel
channel是一种类型安全的消息队列,用以充当两个goroutine之间的消息通道。go语言的并发模型是CSP(Communicating Sequential Processes),提倡通过通信共享内存而不是通过共享内存而实现通信。
go语言中的channel是一种特殊的类型,遵循先入先出的规则,保证数据的收发顺序。
无缓冲通道
//创建语法
ch := make(chan int)
无缓冲通道没有容量,因此无缓冲的通道只有在有接收者的时候才能发送,否则会形成死锁,相反如果接收操作先执行,接收方的goroutine将阻塞,直到另一个goroutine在该通道上发送一个值。
func main() {
ch := make(chan int)
go func() {
fmt.Println(<-ch)
}()
ch <- 10
}
无缓冲管道的本质是为保证同步
有缓冲通道
//创建语法
ch := make(chan int, 10) //创建缓冲为10的通道
只要通道的容量大于零,那么该通道就是有缓冲的通道,通道的容量表示通道中能存放元素的数量,当通道的容量已满时将会阻塞发送者使其等待缓冲通道可用,而当缓冲通道为空的时候会阻塞接收者使其等待资源被发送。
channel内置的len函数可以获取通道内元素的数量,使用cap函数获取通道的容量。
常见异常

References
https://www.cnblogs.com/lxmhhy/p/6041001.html
https://blog.csdn.net/liangzhiyang/article/details/52669851
https://www.cnblogs.com/sunsky303/p/9705727.html
https://zhuanlan.zhihu.com/p/265670936
https://zhuanlan.zhihu.com/p/88878287
https://www.bilibili.com/read/cv10112308/
https://pkg.go.dev/golang.org/x/sync/errgroup
https://mp.weixin.qq.com/s/NcrENqRyK9dYrOBBI0SGkA
https://www.jianshu.com/p/8fbbf6c012b2
https://www.jianshu.com/p/24ede9e90490
https://www.liwenzhou.com/posts/Go/14_concurrence/#autoid-1-4-3
go语言并发编程的更多相关文章
- Go语言 并发编程
Go语言 并发编程 作者:Eric 微信:loveoracle11g 1.创建goroutine // 并行 是两个队列同时使用两台咖啡机 // 并发 是两个队列交替使用一台咖啡机 package m ...
- 融云开发漫谈:你是否了解Go语言并发编程的第一要义?
2007年诞生的Go语言,凭借其近C的执行性能和近解析型语言的开发效率,以及近乎完美的编译速度,席卷全球.Go语言相关书籍也如雨后春笋般涌现,前不久,一本名为<Go语言并发之道>的书籍被翻 ...
- Go语言并发编程总结
转自:http://blog.csdn.net/yue7603835/article/details/44309409 Golang :不要通过共享内存来通信,而应该通过通信来共享内存.这句风靡在Go ...
- Go语言并发编程示例 分享(含有源代码)
GO语言并发示例分享: ppt http://files.cnblogs.com/files/yuhan-TB/GO%E8%AF%AD%E8%A8%80.pptx 代码, 实际就是<<Go ...
- Python3 与 C# 并发编程之~ 线程篇
2.线程篇¶ 在线预览:https://github.lesschina.com/python/base/concurrency/3.并发编程-线程篇.html 示例代码:https://gith ...
- 11 go并发编程-上
其他编程语言并发编程的效果 并发编程可以让开发者实现并行的算法以及编写充分利用多核处理器和多核性能的程序.在当前大部分主流的编程语言里,如C,C++,java等,编写维护和调试并发程序相比单线程程序而 ...
- golang:并发编程总结
并行和并发 并发编程是指在一台处理器上"同时"处理多个任务. 宏观并发:在一段时间内,有多个程序在同时运行. 微观并发:在同一时刻只能有一条指令执行,但多个程序指令被快速的轮换执行 ...
- 《Go并发编程实战》读书笔记-初识Go语言
<Go并发编程实战>读书笔记-初识Go语言 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 在讲解怎样用Go语言之前,我们先介绍Go语言的特性,基础概念和标准命令. 一. ...
- c++ 11开始语言本身和标准库支持并发编程
c++ 11开始语言本身和标准库支持并发编程,意味着真正要到编译器从语言和标准库层面开始稳定,估计得到17标准出来.14稳定之后的事情了,根据历史经验,新特性的引入到稳定被广泛采用至少要一个大版本的跨 ...
随机推荐
- mysql创建用户及赋予某用户权限(附带基础查看表内容)
首先登陆mysql 一:show databases; 展示所有数据库(root用户下) 二:use xxx (数据库名)使用use选择数据库 三:show xxx 查看数据库中的表 四:des ...
- Python中的sys.stdin和input、sys.stdout与print--附带讲解剑指offer42-连续子数组的最大和
2020秋招季,终于开始刷第一套真题了,整套试卷就一道编程题,还是剑指offer上的原题,结果答案死活不对,最后干脆直接提交答案算了,看了下别人的答案,原来是输入数据没有获取的原因,不过这个语法sys ...
- 来说说JPA、Hibernate、Spring Data JPA之间的什么关系?
目录 JPA Hibernate Spring Data JPA 实践 来说说JPA.Hibernate.Spring Data JPA之间的什么关系 Java 持久层框架访问数据库的方式大致分为两种 ...
- 264.丑数II
题目 给你一个整数 n ,请你找出并返回第 n 个 丑数 . 丑数 就是只包含质因数 2.3 和/或 5 的正整数. 示例 1: 输入:n = 10 输出:12 解释:[1, 2, 3, 4, 5, ...
- 一文看懂JVM内存区域分布与作用
那么我们在开始介绍Java内存区域之前,我们先放一张内存区域的图,方便我们后面介绍的时候可以对照着看. 须知,本文是根据JDK8来介绍的. 程序计数器 首先它是线程私有的,它也称为代码的行号指示器,字 ...
- BUAA软工-结对项目作业
结对项目作业 项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任健) 这个作业的要求在哪里 结对项目作业 我在这个课程的目标是 通过这门课锻炼软件开发能力和经验,强化与他人合作 ...
- csp-s 2021
T1 廊桥分配 当一架飞机抵达机场时,可以停靠在航站楼旁的廊桥,也可以停靠在位于机场边缘的远机位. 乘客一般更期待停靠在廊桥,因为这样省去了坐摆渡车前往航站楼的周折. 然而,因为廊桥的数量有限,所以这 ...
- 华为HG255D挂卡中继专用旋风科技固件
正的挂卡不掉线不掉速,稳定上网看上去好像很NB的样子 挂卡设置教程:http://picimg.lshou.com/pic/clou ... /6/t/1/30247515.mp4 固件链接: htt ...
- Linux资料 帮你理清思路
很多同学接触linux不多,对linux平台的开发更是一无所知. 而现在的趋势越来越表明,作为一个优秀的软件开发人员,或计算机it行业从业人员,="" 掌握linux是一种很重要的 ...
- Exynos4412 中断处理流程详解
Linux 中,当外设触发中断后,大体处理流程如下: a -- 具体CPU architecture相关的模块会进行现场保护,然后调用machine driver对应的中断处理handler; b - ...