Go 并发 第1部分:基础与同步
Source: Dev.to
基础并发与同步
首先先了解这两个词的含义
Concurrency
定义是:在同一时间段内处理多个任务的能力
每个任务不一定要同时执行,只要交替执行也算并发
关键特征是每个任务的起始时间有 overlap
Parallelism
定义是:能够同时在硬件上处理多个任务,需要硬件支持
注意:并发可以是并行,也可以不是,这取决于与硬件的映射
即使没有并行运行,并发仍能提升速度,因为一般任务会等待某些操作(例如从内存读取或写入),在等待期间切换到其他任务可以提升整体效率
Go 语言中的并发
Go 内置并发,无需依赖外部库
GOMAXPROCS
设置可同时运行 Go 代码的 OS 线程数
runtime.GOMAXPROCS(4) // ตั้งค่าจากโค้ด
或通过环境变量
export GOMAXPROCS=4
从 Go 1.5 起,GOMAXPROCS 的默认值等于机器的逻辑 CPU 数量,通常不需要修改。设置过高可能导致上下文切换增多,反而降低性能
Goroutine
Go 使用 goroutine,它是轻量级线程(在单个 OS 线程中可以有数千甚至数万),由 Go Runtime Scheduler 调度
程序启动时会创建第一个 goroutine,称为 main routine。要实现并发,只需在函数调用前加上关键字 go
基础示例
package main
import (
"fmt"
"time"
)
func main() {
go fmt.Println("New Routine")
fmt.Println("Main Routine")
}
运行结果只会看到
Main Routine
因为 main() 在新 goroutine 执行前就结束了
正确等待 goroutine 的方式
不建议使用 time.Sleep,因为无法确定需要等待多长时间。推荐使用同步机制,例如 sync.WaitGroup
使用 sync 包进行同步
sync.WaitGroup
WaitGroup 用于记录需要等待的任务计数
Add(n)– 增加计数Done()– 任务完成后递减计数Wait()– 等待计数归零
示例
package main
import (
"fmt"
"sync"
)
func foo(wg *sync.WaitGroup) {
fmt.Println("New Routine")
wg.Done() // บอกว่ารันจบแล้ว
}
func main() {
var wg sync.WaitGroup
wg.Add(2) // มี 2 งานที่ต้องรอ
go foo(&wg)
go foo(&wg)
wg.Wait() // รอจนกว่างานทั้งหมดเสร็จ
fmt.Println("Main Routine")
}
输出
New Routine
New Routine
Main Routine
sync.Once
Once 确保指定函数只会执行一次,即使被多个 goroutine 调用
示例
package main
import (
"fmt"
"sync"
)
func setup() {
fmt.Println("Setup")
}
func main() {
var once sync.Once
var wg sync.WaitGroup
for i := 0; i // (โค้ดตัวอย่างนี้ยังไม่สมบูรณ์ในต้นฉบับ)
}
注意:在 Go 中我们通常避免直接共享全局变量并修改其值,而是使用 channel,这将在下一篇文章中说明.