Go 语言以其出色的并发模型而闻名,在 Linux 平台上提供了多种并发控制机制。以下是主要的并发控制方法:
Goroutine 是 Go 的轻量级线程,由 Go 运行时管理:
go func() {
// 并发执行的代码
}()
Channel 是 Go 的核心并发原语,用于 Goroutine 间通信:
ch := make(chan int)
// 发送数据
go func() {
ch <- 42
}()
// 接收数据
value := <-ch
sync.WaitGroup
用于等待一组 Goroutine 完成:
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
fmt.Println(i)
}(i)
}
wg.Wait() // 等待所有 Goroutine 完成
sync.Mutex
用于保护共享资源:
var (
counter int
mu sync.Mutex
)
func increment() {
mu.Lock()
defer mu.Unlock()
counter++
}
sync.RWMutex
提供更高效的读写控制:
var (
data map[string]string
rwMux sync.RWMutex
)
// 读操作
func read(key string) string {
rwMux.RLock()
defer rwMux.RUnlock()
return data[key]
}
// 写操作
func write(key, value string) {
rwMux.Lock()
defer rwMux.Unlock()
data[key] = value
}
sync.Once
确保某操作只执行一次:
var once sync.Once
func setup() {
once.Do(func() {
// 只执行一次的初始化代码
})
}
context
包用于控制 Goroutine 的生命周期:
ctx, cancel := context.WithCancel(context.Background())
go func(ctx context.Context) {
select {
case <-ctx.Done():
return // 被取消
case <-time.After(time.Second):
fmt.Println("工作完成")
}
}(ctx)
// 取消操作
cancel()
select
语句用于监听多个 Channel:
select {
case msg1 := <-ch1:
fmt.Println(msg1)
case msg2 := <-ch2:
fmt.Println(msg2)
case <-time.After(time.Second):
fmt.Println("超时")
}
sync/atomic
包提供原子操作:
var count int32
atomic.AddInt32(&count, 1) // 原子增加
使用缓冲 Channel 实现工作池:
func worker(id int, jobs <-chan int, results chan<- int) {
for j := range jobs {
fmt.Println("worker", id, "processing job", j)
results <- j * 2
}
}
jobs := make(chan int, 100)
results := make(chan int, 100)
// 启动 3 个 worker
for w := 1; w <= 3; w++ {
go worker(w, jobs, results)
}
// 发送 9 个任务
for j := 1; j <= 9; j++ {
jobs <- j
}
close(jobs)
// 收集结果
for a := 1; a <= 9; a++ {
<-results
}
runtime.GOMAXPROCS()
控制使用的 CPU 核心数go tool trace
- 可视化并发执行pprof
- 性能分析-race
标志 - 检测数据竞争Go 的并发模型在 Linux 平台上表现优异,合理使用这些并发控制机制可以构建高效可靠的并发程序。