参考文档:www.topgoer.com
使用方法
直接包装成函数,go关键字触发即可
注意事项
1 main方法结束后,main方法内启动的子协程会立即结束,无论是否执行完毕;
启动多个groutine
使用sync包的WaitGroup来控制,等待每一个协程执行完毕:
go
package main
import (
"fmt"
"sync"
"time"
)
func printHello(wg *sync.WaitGroup) {
time.Sleep(3 * time.Second)
defer wg.Done()
fmt.Println("__hello__")
}
func main() {
var wg sync.WaitGroup
wg.Add(3)
go printHello(&wg)
go printHello(&wg)
go printHello(&wg)
wg.Wait()
}
要知道协程执行顺序,以上代码可以修改为:
go
package main
import (
"fmt"
"sync"
"time"
)
var wg sync.WaitGroup
func printHello(i int) {
defer wg.Done()
time.Sleep(3 * time.Second)
fmt.Printf("__hello:%d__\n", i)
}
func main() {
for i := 0; i < 10; i++ {
wg.Add(1)
go printHello(i)
}
wg.Wait()
}
根据打印结果来看,执行是无序的。
goroutine与线程
goroutine生命周期开始时的栈默认只有2kb,可以按需增大或缩小,最大可到1GB,一次性创造10万个goroutine也是可以的。
goroutine调度
GPM是Go语言运行时(runtime)层面的实现,是go语言自己实现的一套调度系统。区别于操作系统调度OS线程;
G:goroutine
P:processor处理器,管理着一组goroutine队列,P里面会存储当前goroutine运行的上下文环境(函数指针,堆栈地址及地址边界),P会对自己管理的goroutine队列做一些调度
M:machine,是Go运行时(runtime)对操作系统内核线程的虚拟, M与内核线程一般是一一映射的关系, 一个groutine最终是要放到M上执行的。
P与M一般也是一一对应的。他们关系是: P管理着一组G挂载在M上运行。当一个G长久阻塞在一个M上时,runtime会新建一个M,阻塞G所在的P会把其他的G 挂载在新建的M上。当旧的G阻塞完成或者认为其已经死掉时 回收旧的M