- OS线程(操作系统线程)一般都有固定的栈内存(通常为2MB
- 一个goroutine的栈在其生命周期开始时只有很小的栈(典型情况下2KB)
- goroutine的栈不是固定的,他可以按需增大和缩小,goroutine的栈大小限制可以达到1GB,虽然极少会用到这个大。
- 在Go语言中一次创建十万左右的goroutine也是可以的。
-
G:表示 goroutine,每执行一次go f()就创建一个 G,包含要执行的函数和上下文信息。
-
全局队列(Global Queue):存放等待运行的 G。
-
P:表示 goroutine 执行所需的资源,最多有 GOMAXPROCS 个。
-
P 的本地队列:同全局队列类似,存放的也是等待运行的G,存的数量有限,不超过256个。新建 G 时,G 优先加入到 P 的本地队列,如果本地队列满了会批量移动部分 G 到全局队列。
-
M:线程想运行任务就得获取 P,从 P 的本地队列获取 G,当 P 的本地队列为空时,M 也会尝试从全局队列或其他 P 的本地队列获取 G。M 运行 G,G 执行之后,M 会从 P 获取下一个 G,不断重复下去。
-
Goroutine 调度器和操作系统调度器是通过 M 结合起来的,每个 M 都代表了1个内核线程,操作系统调度器负责把内核线程分配到 CPU 的核上执行。
单从线程调度讲,Go语言相比起其他语言的优势在于OS线程是由OS内核来调度的, goroutine 则是由Go运行时(runtime)自己的调度器调度的,完全是在用户态下完成的, 不涉及内核态与用户态之间的频繁切换,包括内存的分配与释放,都是在用户态维护着一块大的内存池, 不直接调用系统的malloc函数(除非内存池需要改变),成本比调度OS线程低很多。 另一方面充分利用了多核的硬件资源,近似的把若干goroutine均分在物理线程上, 再加上本身 goroutine 的超轻量级,以上种种特性保证了 goroutine 调度方面的性能。
runtime runtime.Gosched()Gosched yields the processor, allowing other goroutines to run.
让出CPU时间片,允许其他goroutine执行。
func main() {
go func(s string) {
for i := 0; i < 2; i++ {
fmt.Println(s)
}
}("world")
// 主协程
for i := 0; i < 2; i++ {
// 切一下,再次分配任务
runtime.Gosched()
fmt.Println("hello")
}
}
------------------------------不加Gosched()结果
hello
hello
(主协程翘辫子了,子协程不会执行)
------------------------------加了Gosched()结果
world
world
hello
hello
runtime.Goexit()
Goexit terminates the goroutine that calls it. No other goroutine is affected.
Goexit runs all deferred calls before terminating the goroutine.
本函数终止一个goroutine, 并且会执行所有deferr。
func main() {
go func() {
defer fmt.Println("A.defer")
func() {
defer fmt.Println("B.defer")
// 结束协程
runtime.Goexit()
defer fmt.Println("C.defer")
fmt.Println("B")
}()
fmt.Println("A")
}()
// 用于阻塞主协程
for {;
}
}
-----------------------------------执行结果
B.defer
A.defer
runtime.GOMAXPROCS
GOMAXPROCS sets the maximum number of CPUs that can be executing
Go运行时的调度器使用GOMAXPROCS参数来确定需要使用多少个 OS 线程来同时执行 Go 代码。默认值是机器上的 CPU 核心数。例如在一个 8 核心的机器上,GOMAXPROCS 默认为 8。Go语言中可以通过runtime.GOMAXPROCS函数设置当前程序并发时占用的 CPU逻辑核心数。
Go语言中的操作系统线程和goroutine的关系:1.一个操作系统线程对应用户态多个goroutine。
2.go程序可以同时使用多个操作系统线程。
3.goroutine和OS线程是多对多的关系,即m:n。



