go语言实现三个并发 go语言 并发

go语言--Goroutines1、goroutine:在go语言中 , 每一个并发的执行单元叫做goroutine,如果一个程序中包含多个goroutine , 对两个函数的调用则可能发生在同一时刻
2、main goroutine:当一个程序启动时 , 其主函数即在一个单独的goroutine中运行,我们叫他为main gorountine
3、go goroutine:新的goroutine会用go语句来创建,go+函数名,go语句会使其语句中的函数在一新创建的goroutine中运行 , 而go语句本身会迅速地完成
4、goroutine的退出:主函数返回时,所有的goroutine都会被直接打断,程序退出,除了从主函数退出或者终止程序之外,没有其他方法能够让一个goroutine来打断另一个的执行,但是可以通过另一种方式来实现这个目的,通过goroutine之间的通信来让一个goroutine请求其他的goroutine,并让请求的goroutine自行结束执行
Go CSP并发模型Go的CSP并发模型
Go实现了两种并发形式 。第一种是大家普遍认知的:多线程共享内存 。其实就是Java或者C++等语言中的多线程开发 。另外一种是Go语言特有的 , 也是Go语言推荐的:CSP(communicating sequential processes)并发模型 。
CSP 是 Communicating Sequential Process 的简称 , 中文可以叫做通信顺序进程,是一种并发编程模型,由 Tony Hoare 于 1977 年提出 。简单来说 , CSP 模型由并发执行的实体(线程或者进程)所组成,实体之间通过发送消息进行通信,这里发送消息时使用的就是通道,或者叫 channel 。CSP 模型的关键是关注 channel,而不关注发送消息的实体 。Go 语言实现了 CSP 部分理论。
“不要以共享内存的方式来通信,相反,要通过通信来共享内存 。”
Go的CSP并发模型 , 是通过goroutine和channel来实现的 。
goroutine 是Go语言中并发的执行单位 。其实就是协程 。
【go语言实现三个并发 go语言 并发】channel是Go语言中各个并发结构体(goroutine)之前的通信机制 。通俗的讲,就是各个goroutine之间通信的”管道“,有点类似于Linux中的管道 。
Channel
Goroutine
Go语言——goroutine并发模型参考:
Goroutine并发调度模型深度解析手撸一个协程池
Golang 的 goroutine 是如何实现的?
Golang - 调度剖析【第二部分】
OS线程初始栈为2MB 。Go语言中,每个goroutine采用动态扩容方式,初始2KB,按需增长,最大1G 。此外GC会收缩栈空间 。
BTW,增长扩容都是有代价的,需要copy数据到新的stack,所以初始2KB可能有些性能问题 。
更多关于stack的内容 , 可以参见大佬的文章 。聊一聊goroutine stack
用户线程的调度以及生命周期管理都是用户层面 , Go语言自己实现的,不借助OS系统调用 , 减少系统资源消耗 。
Go语言采用两级线程模型,即用户线程与内核线程KSE(kernel scheduling entity)是M:N的 。最终goroutine还是会交给OS线程执行,但是需要一个中介 , 提供上下文 。这就是G-M-P模型
Go调度器有两个不同的运行队列:
go1.10\src\runtime\runtime2.go
Go调度器根据事件进行上下文切换 。
调度的目的就是防止M堵塞 , 空闲 , 系统进程切换 。
详见Golang - 调度剖析【第二部分】
Linux可以通过epoll实现网络调用,统称网络轮询器N(Net Poller) 。
文件IO操作
上面都是防止M堵塞,任务窃取是防止M空闲
每个M都有一个特殊的G,g0 。用于执行调度,gc , 栈管理等任务,所以g0的栈称为调度栈 。g0的栈不会自动增长,不会被gc , 来自os线程的栈 。

推荐阅读