1.什么是协程?
协程又称为微线程,是一种比线程更加轻量级的存在。正如一个进程可以拥有多个线程,一个线程也可以拥有多个协程。
协程是编译器级的,进程和线程是操作系统级的。协程不被操作系统内核管理,而完全由程序控制,因此没有线程切换的开销。
2.Goroutine
Go
语言中的协程叫作Goroutine
。Goroutine
由Go
程序运行时(runtime
)调度和管理,Go
程序会智能地将Goroutine
中的任务合理地分配给每个CPU
。创建Goroutine
的成本很小,每个Goroutine
的堆栈只有几kb
,且堆栈可以根据应用程序的需要增长和收缩。
2.1 Coroutine与Goroutine的区别
-
Goroutine
能并行执行,Coroutine
只能顺序执行; -
Goroutine
可在多线程环境产生,Coroutine
只能发生在单线程。 -
Coroutine
程序需要主动交出控制权,系统才能获得控制权并将控制权交给其他Coroutine
。 -
Coroutine
的运行机制属于协作式任务处理,应用程序在不使用CPU
时,需要主动交出CPU
使用权。如果开发者无意间让应用程序长时间占用CPU
,操作系统也无能为力,计算机很容易失去响应或者死机。 -
Goroutine
属于抢占式任务处理,和现有的多线程和多进程任务处理非常类似。应用程序对CPU
的控制最终由操作系统来管理,如果操作系统发现一个应用程序长时间占用CPU
,那么用户有权终止这个任务。
3.普通函数创建Goroutine
3.1 创建语法
使用go
关键字创建Goroutine
时,被调用的函数往往没有返回值,如果有返回值也会被忽略。如果需要在Goroutine中返回数据,必须使用channel,通过channel把数据从Goroutine中作为返回值传出。
// 创建Goroutine
go funcName()
3.2 使用
package main
import (
"fmt"
"strconv"
"time"
)
func main() {
go echoNum("张三")
go echoNum("李四")
go echoNum("王五")
// 睡眠1秒
time.Sleep(1 * time.Second)
fmt.Println("运行结束")
}
// 报数
func echoNum(who string) {
for i := 1; i < 3; i++ {
fmt.Println(who + " "+ strconv.Itoa(i))
}
}
/** 输出
张三 1
张三 2
王五 1
李四 1
李四 2
王五 2
运行结束
*/
4. 匿名函数创建Goroutine
4.1 创建语法
go func(){
// ...函数体
}()
4.2 使用
package main
import (
"fmt"
"strconv"
"time"
)
func main() {
go func(who string) {
for i := 1; i < 3; i++ {
fmt.Println(who + " "+ strconv.Itoa(i))
}
}("张三")
go func(who string) {
for i := 1; i < 3; i++ {
fmt.Println(who + " "+ strconv.Itoa(i))
}
}("李四")
go func(who string) {
for i := 1; i < 3; i++ {
fmt.Println(who + " "+ strconv.Itoa(i))
}
}("王五")
// 睡眠1秒
time.Sleep(1 * time.Second)
fmt.Println("运行结束")
}
/** 输出
张三 1
张三 2
王五 1
王五 2
李四 1
李四 2
运行结束
*/
多个Goroutine随机调度,打印的结果是数字与字母交叉输出
5. 并发运行性能调整
5.1 设置运行的 cpu 数
为了充分了利用多 cpu
的优势,在Golang
程序中,可以通过runtime.GOMAXPROCS()
函数 设置运行的 cpu
数目
-
使用格式
runtime.GOMAXPROCS( 逻辑CPU)
//逻辑CPU可以通过 runtime.NumCpu()函数获取
这里的逻辑CPU数量可以有如下几种数值:
数值 | 含义 | 示例 |
---|---|---|
< 1 | 不修改任何数值 | runtime.GOMAXPROCS(0) |
= 1 | 单核执行 | runtime.GOMAXPROCS(1) |
> 1 | 多核并发执行 | runtime.GOMAXPROCS(4) 4核并发执行 |
Go 1.5版本之前,默认使用的是单核心执行。从Go 1.5版本开始,默认执行 runtime.GOMAXPROCS(逻辑CPU数量)
,让代码并发执行,最大效率地利用CPU。GOMAXPROCS
同时也是一个环境变量,在应用程序启动前设置环境变量也可以起到相同的作用。
6.注意事项
-
所有 Goroutine
在main()
函数结束时会一同结束。 -
如果需要在 Goroutine
中返回数据,必须使用channel
,通过channel
把数据从Goroutine
中作为返回值传出。 -
启动多个 Goroutine
时,会随机调度。
微信搜索关注【猿码记】查看更多文章。
本文由 mdnice 多平台发布