文章目录
-
- [go func 和 WaitGroup](#go func 和 WaitGroup)
- [协程 v.s. 线程](#协程 v.s. 线程)
- [GMP 并发模型](#GMP 并发模型)
go func 和 WaitGroup
- 在 Go 语言中,协程(goroutine)之间并没有严格的父子关系。一个协程中可以启动其他协程,即使启动它的协程已经结束,所启动的新协程仍会继续运行,直到自身执行完毕。
- 但需要注意的是,main 函数运行在特殊的主协程中。一旦 main 函数返回,整个程序的运行时(runtime)也会随之退出,此时即使还有其他协程未执行完毕,也会被强制终止。
go
package main
import (
"fmt"
"time"
)
func parent() {
for i := 'a'; i <= 'z'; i++ {
fmt.Printf("%d\n", i)
time.Sleep(500 * time.Microsecond)
}
}
func child() {
for i := 'a'; i <= 'z'; i++ {
fmt.Printf("%c\n", i)
time.Sleep(500 * time.Microsecond)
}
}
func main() {
go parent()
go child()
fmt.Println("main")
}
// 输出
zhengjia@MacBook-Air Sys % go run "/Users/zhengjia/Downloads/Sys/main.go"
main
time.Sleep(100000 * time.Microsecond)
加上这段才能保证两个go程交替运行,但是这样每次都要强行等固定时间,会造成资源浪费,能不能让两个go程执行完后自动终止runtime呢?- 在 Go(Golang)语言中,sync.WaitGroup 是一个用于协程(goroutine)同步的重要工具。它可以用来等待一组 goroutine 全部执行完成,常用于并发任务的控制。它通过一个计数器来跟踪未完成的任务数量,并提供简单的方法来管理这个计数器。

go
package main
import (
"fmt"
"sync"
"time"
)
var (
wg = sync.WaitGroup{}
)
func parent() {
defer wg.Done()
wg.Add(1)
go child()
for i := 'a'; i <= 'z'; i++ {
fmt.Printf("%d\n", i)
time.Sleep(500 * time.Microsecond)
}
}
func child() {
defer wg.Done()
for i := 'a'; i <= 'z'; i++ {
fmt.Printf("%c\n", i)
time.Sleep(500 * time.Microsecond)
}
}
func main() {
wg.Add(1)
go parent()
// 匿名函数
go func() {
defer wg.Done()
wg.Add(1)
go child()
for i := 'a'; i <= 'z'; i++ {
fmt.Printf("%d\n", i)
time.Sleep(500 * time.Microsecond)
}
}()
fmt.Println("main")
wg.Wait() // 不为0就一直阻塞
}
协程 v.s. 线程


- go中线程和协程并不是绑定的,一个协程可能中途会换一系列内核线程去执行,这和Java、CPP有着明显区别。
GMP 并发模型


- M 执行 G,但必须通过绑定一个 P 才能运行
- P 拥有一个本地的 G 队列,将 G 分配给 M
- 多个 G 可以由多个 M 并发执行,但同时执行的数量受限于 P 的数量
