当前位置:网站首页>go笔记之——goroutine
go笔记之——goroutine
2022-08-02 00:13:00 【Meme_xp】
goroutine底层实现原理!!!!!!!!!!!!!
概念
Goroutine可以理解为一种Go语言的协程(轻量级线程),是Go支持高并发的基础,属于用户态的线程,由Goruntime管理而不是操作系统。
底层数据结构存储了非常多的上下文:
底层数据结构:

最终是一个runtime.g对象放入了队列
状态流转:

状态轮转图

1.创建
通过go关键字调用底层函数runtime.newproc()创建一个goroutine当调用该函数之后goroutine会被设置成runnable状态
func main( ) {
go func() {
fmt.Println("func routine"")
}()
fmt.Println("main goroutine")
}
创建好的这个goroutine会新建一个自己的栈空间,同时在G的sched中维护栈地址与程序计数器这些信息。每个G在被创建之后,都会被优先放入到本地队列中,如果本地队列已经满了,就会被放入到全局队列中。
2.运行
goroutine本身只是一个数据结构,真正让goroutine运行起来的是调度器。Go实现了一个用户态的调度器(GMP模型),这个调度器充分利用现代计算机的多核特性,同时让多个goroutine运行,同时goroutine设计的很轻量级,调度和上下文切换的代价都比较小。

3.调度时机
调度时机
新起一个协程和协程执行完毕
会阻塞的系统调用,比如文件io、网络io. channel、mutex等阻塞操作
time.sleep
垃圾回收之后主动调用runtime.Gosched()·运行过久或系统调用过久等等
先本地g执行,执行完全局拿(每次全局拿记得上锁,防止被多次拿),全局拿玩就去其他本地队列偷,每次偷一半(下取整),如果没得偷的了就自旋,每次最多有设定好的个数自旋等待新的任务,防止cpu浪费资源
4.阻塞
channel的读写操作、等待锁、等待网络数据、系统调用等都有可能发生阻塞,会调用底层函
数runtime.gopark(),会让出CPU时间片,让调度器安排其它等待的任务运行,并在下次某个时候从该位置恢复执行。
当调用该函数之后,goroutine会被设置成waiting状态
5.唤醒
处于waiting状态的goroutine,在调用runtime.goready()函数之后会被唤醒,唤醒的goroutine会被重新放到M对应的上下文P对应的runqueue中,等待被调度。
当调用该函数之后,goroutine会被设置成runnable状态
6.退出
当goroutine执行完成后,会调用底层函数runtime.Goexit()。当调用该函数之后,goroutine会被设置成dead 状态
goroutine和线程的区别

goroutine泄露场景
泄漏原因
1.Goroutine内进行channel/mutex等读写操作被一直阻塞。
2.Goroutine内的业务逻辑进入死循环,资源一直无法释放。
3.Goroutine内的业务逻辑进入长时间等待,有不断新增的Goroutine进入等待
泄露场景
1.如果输出的goroutines数量是在不断增加的,就说明存在泄漏
2.nil channel,对空channel读写
3.channel如果忘记初始化,那么无论你是读,还是写操作,都会造成阻塞。
1.nil channel
func main() {
fmt.Println("before goroutines: ",runtime.NumGoroutine( ) )
block1()
time.Sleep(time.Second * 1)
fmt.Println("after goroutines: ", runtime.NumGoroutine()
}
func block1() {
var ch chan int
for i := 0; i < 10; i++ {
go func() {
<-ch3}()
}
}

2.接受不发送
channel发送数量草果channel接收数量,造成了阻塞
func block2() {
ch := make( chan int)
for i := 0; i < 10; i++ {
go func() {
ch <- 1}()
}
}
3.只接受不发送
channel接收数量超过了channelf发送的数量,也会造成阻塞
func block3( ) {
ch := make(chan int)
for i := 0; i < 10; i++ {
go func() {
<-ch}()
}
}
4.http request body未关闭
resp.Body.Close(),为被调用,groutine不会退出
5.互斥锁忘记解锁
第一个协程获取sync.Mutex加锁了,但是他可能在处理业务逻辑,又或是忘记Unlock 了。
因此导致后面的协程想加锁,却因锁未释放被阻塞了
func block5() {
var mutex sync.Mutex
for i := 0; i < 10; i++ {
go func() {
mutex.Lpck()}()
}
}
6.sync.WaitGroup原语使用不当
由于wg.Add的数量与wg.Done 数量并不匹配,因此在调用wg.wait方法后一直阻塞等待
func block6() {
var wg sync.waitGroup
for i := 0; i < 10; i++ {
go func() {
wg.Add(2)
wg.Done()
wg.wait()}()
}
}
如何排查
1.单个函数︰调用runtime.NumGoroutine方法来打印执行代码前后Goroutine的运行数量,进行前后比较,就能知道有没有泄露了。
2.生产/测试环境:使用PProf 实时监测Goroutine的数量
如何查看正在执行的goroutine的数量?
因为go服务一般是在线服务,所以我们引入pprof package
//在程序中引入pprof package
import _ "net/http/pprof"


如何控制并发的goroutine数量
为什么要控制goroutine并发的数量?
在开发过程中,如果不对goroutine加以控制而进行滥用的话,可能会导致服务整体崩溃。比如耗尽系统资源导致程序崩溃,或者CPU使用率过高导致系统忙不过来。
用什么方法控制goroutine并发的数量?
有缓冲channel利用缓冲满时发送阻塞的特性

有数据才创建!!!!!!!!!!!!这里最多支持三个goroutine
边栏推荐
- What is it like to trade for a living?
- 众筹DAO“枯萎”的缩影:曾拍下《沙丘》未出版手稿的Spice DAO解散
- els block boundary deformation processing
- 玩转NFT夏季:这份工具宝典值得收藏
- 回顾历史5次经济衰退时期:这一次可能会有何不同?
- String splitting function strtok exercise
- Statement执行update语句
- Stapler:1 靶机渗透测试-Vulnhub(STAPLER: 1)
- unity2D横版游戏教程5-UI
- 2022/08/01 学习笔记 (day21) 泛型和枚举
猜你喜欢

扑克牌问题

Double queue implementation stack?Dual stack implementation queue?

An overview of the most useful DeFi tools

NFT工具合集

【HCIP】BGP小型实验(联邦,优化)

Short video SEO optimization tutorial Self-media SEO optimization skills and methods

Arduino 基础语法

22. The support vector machine (SVM), gaussian kernel function

632. Minimum interval

632. 最小区间
随机推荐
ICML 2022 || 局部增强图神经网络GNN,在 GCN 和 GAT基础上 平均提高了 3.4% 和 1.6%
Knowing the inorder traversal of the array and the preorder traversal of the array, return the postorder history array
使用jOOQ将Oracle风格的隐式连接自动转换为ANSI JOIN
MySQL常用语句整理
[Solution] Emqx startup under win10 reports Unable to load emulator DLL, node.db_role = EMQX_NODE__DB_ROLE = core
Mean Consistency Tracking of Time-Varying Reference Inputs for Multi-Agent Systems with Communication Delays
这 4 款电脑记事本软件,得试试
Don't know about SynchronousQueue?So ArrayBlockingQueue and LinkedBlockingQueue don't and don't know?
C language character and string function summary (2)
Unknown CMake command "add_action_files"
JSP request对象功能详解说明
什么是低代码(Low-Code)?低代码适用于哪些场景?
460. LFU cache
攻防世界-web-Training-WWW-Robots
An interesting project--Folder comparison tool (1)
How to find new potential projects?Tools recommended
nodeJs--mime模块
2022/08/01 Study Notes (day21) Generics and Enums
els block boundary deformation processing
els 方块边界变形处理