Skip to main content

goroutine

一 Golang对协程的支持

Go语言从语言层面原生提供了协程支持,即 goroutine,执行goroutine只需极少的栈内存(大概是4~5KB),所以Go可以轻松的运行多个并发任务。

Go中以关键字 go 开启协程:

func say(s string) {
for i := 0; i < 3; i++ {
fmt.Println(s)
}
}

func main() {
go say("Go") // 以协程方式执行say函数
say("noGo") // 以普通方式执行say函数
time.Sleep(5 * time.Second) // 睡眠5秒:防止协程未执行完毕,主程序退出
}

上述的程序的打印结果并不是按照顺序的,因为go关键字开启了协程,两个say函数并不是在一个控制流中!

二 goroutine使用案例

2.1 同时执行两件事

func running() {
var times int
for {
times++
fmt.Println("tick:", times)
time.Sleep(time.Second)
}
}

func main() {
go running()
var input string
fmt.Scanln(&input)
}

命令行会不断地输出 tick,同时可以使用 fmt.Scanln() 接受用户输入。两个环节可以同时进行,直到按 Enter键时将输入的内容写入 input变量中井返回, 整个程序终止。

2.2 一道基础面试题

示例一:

for i := 1; i <= 10; i++ {
go func(){
fmt.Println(i) // 全部打印11:因为开启协程也会耗时,协程没有准备好,循环已经走完
}()
}
time.Sleep(time.Second)

示例二:

	for i := 1; i <= 10; i++ {
go func(i int){
fmt.Println(i) // 打印无规律数字
}(i)
}
time.Sleep(time.Second)

三 常用API

3.1 GOMAXPROCS() 多核利用

goroutine相关API位于 runtime 包。

如果Go程序要运行在多核上,则可以如下操作,此时可以实现程序的并行执行:

	cpuNum := runtime.NumCPU()				//获取当前系统的CPU核心数
runtime.GOMAXPROCS(cpuNum) //Go中可以轻松控制使用核心数

贴士:在Go1.5之后,程序已经默认运行在多核上,无需上述设置

3.2 Gosched() 让出时间片

runtime.Gosched():用于让出CPU时间片,即让出当前协程的执行权限,调度器可以去安排其他等待的任务运行。示例如下:

func main(){
for i := 1; i <= 10; i++ {
go func(i int){
if i == 5 {
runtime.Gosched() // 协程让出,但并不代表不执行,而是 5永远不会第一输出
}
fmt.Println(i) // 打印一组无规律数字
}(i)
}
time.Sleep(time.Second)
}

贴士:可以理解为接力赛跑:A跑了一段遇到了Gosched接力给B。

3.3 Goexit() 终止当前协程

runtime.Goexit():用于立即终止当前协程运行,调度器会确保所有已注册defer延迟调用被执行。

func main(){
for i := 1; i <= 5; i++ {
defer fmt.Println("defer ", i)
go func(i int){
if i == 3 {
runtime.Goexit()
}
fmt.Println(i)
}(i)
}
time.Sleep(time.Second)
}

输出的结果类似于:

4
2
5
1
defer 5
defer 4
defer 3
defer 2
defer 1