Go 并发编程协程及调度机制详情
什么是协程
Go语言引入了协程的概念,也称为轻量级线程或用户态线程。协程是一种由用户自己管理的轻量级线程,不需要由操作系统调度,从而减轻了操作系统的负担。一个进程中可以有多个协程,协程间的切换只需要保存少量的寄存器上下文,并且可以随时进行,因此协程比线程更轻量级、更高效。
协程的使用
协程可以使用go关键字开启,并且可以在函数调用前面加上关键字go实现异步调用。下面是一个简单的使用协程的例子:
package main
import(
"fmt"
"time"
)
func a() {
for i := 0; i < 5; i++ {
fmt.Println("a: ", i)
}
}
func b() {
for i := 0; i < 5; i++ {
fmt.Println("b: ", i)
}
}
func main() {
go a()
go b()
time.Sleep(time.Second * 1)
}
在上面的例子中,使用关键字go开启的函数a和b都是协程,因此可以同时运行而不会相互影响。同时在main函数中使用Sleep函数使得主协程等待了一秒钟再结束,这样可以保证两个协程都可以执行完。
协程的调度机制
每个Go程序都有一个全局的协程调度器,调度器的主要作用是在协程之间进行调度切换,以保证每个协程都能够得到执行。
调度器是通过Goroutine(协程)和P(处理器)实现的。P指的是内核线程,每个P中会维持一个G的Go协程队列的列表。调度器会将正在运行的协程绑定到P上,如果协程要阻塞,就会将它从P的协程队列中移除,然后将P解绑,继续执行其他协程。
当一个协程阻塞时,调度器会从其它空闲的P中找一个空闲的P,并将该协程绑定到它上面。如果没有空闲的P,就会增加P。
示例代码如下:
package main
import (
"fmt"
"time"
)
func a() {
for i := 0; i < 3; i++ {
fmt.Println("a: ", i)
time.Sleep(time.Millisecond * 100)
}
}
func b() {
for i := 0; i < 3; i++ {
fmt.Println("b: ", i)
time.Sleep(time.Millisecond * 100)
}
}
func main() {
go a()
b()
go a()
b()
}
在上面的代码中,开启了两个协程a()和b(),b()函数不使用关键字go,因此会在主协程中运行。在a()函数中使用Sleep函数模拟阻塞,因此a()函数在执行时会阻塞。可以看到在执行过程中,两个a()函数和两个b()函数的输出是交替进行的,这说明调度器在进行了切换。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Go 并发编程协程及调度机制详情 - Python技术站