Go协程(Goroutine)是与其他函数同时运行的函数。可以认为Go协程是轻量级的线程。与创建线程相比,创建Go协程的成本很小。因此在Go中同时运行上千个协程是很常见的。
1、 Go语言的并发性
Go语言原生就支持了高并发操作,这一优秀基因在目前主流的编程语言中是比较少见的,Go语言的高并发性主要是通过 Go协程(Goroutine)来实现的。
协程的特点
- 协程是一个轻量级的线程,此处可以与进程、线程、协程 进行对比
- Go协程是非抢占式多任务处理,需要由协程主动交出控制权
- 协程是一个 虚拟机层面的多任务处理
- 多个协程可能运行在一个或者多个线程上
Go语言实现协程,只需要在函数前添加 go 关键字,就可以使此函数并发执行
示例代码如下:
package main
import (
"fmt"
"time"
)
func main() {
for i := 0; i < 1000; i++ {
go func(i int) {
for {
fmt.Printf("Hello from "+"goroutine %d\n", i)
}
}(i)
}
time.Sleep(time.Millisecond)
}
2、其他语言中的协程
C++ 可以通过 Boost.Coroutine 库实现协程。
Java 不支持协程
Python 3.5 加入了 async def 对协程的支持,但是Python的 协程是在方法定义时就确定了,被定义协程的方法不能当做普通方法来使用,而Go语言中定义方法和协程调用是分开的,任意方法加上go 关键字都可以进行协程并发操作,实现了解耦合。
3、Go语言协程调度器
Go语言中所有的协程都通过调度器进行调度,大并发下成百上千甚至几千的协程调用 通过调度器安排到不同的线程中执行。
调度的切换
调度器会在何时的时间点进行协程之间的切换,通过切换可以将计算资源分配给其他协程而不至于被一个协程锁死资源,主要的切换点如下:
- IO/SELECT
- channel
- 函数调用
- runtime.Gosched() 手动切换
- 等待锁