Go语言并发编程实战
Go语言以其优秀的并发支持而闻名,goroutine和channel是Go并发编程的两大核心概念。相比传统的线程模型,goroutine更轻量、更高效。本文将介绍Go并发编程的核心概念和实战模式。
一、Goroutine基础
// 启动goroutine
go func() {
fmt.Println("Hello from goroutine")
}()
// 等待goroutine完成
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
fmt.Printf("Worker %d working\n", id)
}(i)
}
wg.Wait()
// 限制并发数
sem := make(chan struct{}, 5) // 最多5个并发
for _, url := range urls {
sem <- struct{}{} // 获取信号量
go func(u string) {
defer func() { <-sem }() // 释放信号量
fetch(u)
}(url)
}
二、Channel通信
// 无缓冲channel - 同步通信
ch := make(chan string)
go func() {
ch <- "hello" // 发送(阻塞直到有人接收)
}()
msg := <-ch // 接收
fmt.Println(msg) // hello
// 缓冲channel - 异步通信
ch := make(chan int, 100)
// 生产者
go func() {
for i := 0; i < 1000; i++ {
ch <- i // 缓冲区满时阻塞
}
close(ch)
}()
// 消费者
for val := range ch {
process(val)
}
// select多路复用
select {
case msg := <-ch1:
fmt.Println("ch1:", msg)
case msg := <-ch2:
fmt.Println("ch2:", msg)
case <-time.After(5 * time.Second):
fmt.Println("timeout")
}
三、常见并发模式
// Fan-Out/Fan-In - 扇出扇入
func fanOutFanIn(inputs []string) []Result {
ch := make(chan Result, len(inputs))
// Fan-Out: 多个goroutine处理
for _, input := range inputs {
go func(in string) {
ch <- process(in)
}(input)
}
// Fan-In: 收集结果
var results []Result
for i := 0; i < len(inputs); i++ {
results = append(results, <-ch)
}
return results
}
// Pipeline - 管道模式
func pipeline(input <-chan Data) <-chan Result {
stage1 := processStage1(input)
stage2 := processStage2(stage1)
return processStage3(stage2)
}
// Context取消
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
select {
case result := <-doWork(ctx):
fmt.Println(result)
case <-ctx.Done():
fmt.Println("cancelled:", ctx.Err())
}
四、sync包常用工具
// Mutex - 互斥锁
var mu sync.Mutex
var counter int
func increment() {
mu.Lock()
counter++
mu.Unlock()
}
// sync.Map - 并发安全Map
var m sync.Map
m.Store("key", "value")
val, ok := m.Load("key")
m.Range(func(key, value interface{}) bool {
fmt.Println(key, value)
return true // 继续遍历
})
// sync.Once - 只执行一次
var once sync.Once
once.Do(func() {
// 初始化操作
})
// sync.Pool - 对象池
var pool = sync.Pool{
New: func() interface{} {
return new(Buffer)
},
}
buf := pool.Get().(*Buffer)
// 使用buf...
pool.Put(buf)
Go的并发模型简洁而强大,goroutine的轻量级特性让并发编程变得容易。但要小心并发安全、goroutine泄漏和死锁等问题。建议在开发中使用race detector(go test -race)来检测数据竞争。