jee said
Go语言并发编程详解
Go语言的并发模型是其最强大的特性之一。通过goroutine和channel,Go让并发编程变得简单而高效。
Goroutine
Goroutine是Go语言的轻量级线程,由Go运行时管理。
启动Goroutine
func sayHello() {
fmt.Println("Hello, Goroutine!")
}
func main() {
go sayHello() // 启动goroutine
time.Sleep(time.Second) // 等待goroutine执行
}Goroutine特性
- 轻量级:初始栈大小仅2KB
- 动态扩展:栈空间按需增长
- 高效调度:M:N调度模型
- 简单易用:只需添加
go关键字
Channel
Channel是goroutine之间通信的主要方式,遵循”不要通过共享内存来通信,而要通过通信来共享内存”的理念。
创建和使用Channel
// 创建channel
ch := make(chan int)
// 发送数据
ch <- 42
// 接收数据
value := <-ch缓冲Channel
// 创建缓冲大小为3的channel
ch := make(chan int, 3)
ch <- 1 // 不会阻塞
ch <- 2
ch <- 3Select语句
select {
case msg1 := <-ch1:
fmt.Println("从ch1接收:", msg1)
case msg2 := <-ch2:
fmt.Println("从ch2接收:", msg2)
case <-time.After(time.Second):
fmt.Println("超时")
}Sync包
当需要更细粒度的同步控制时,可以使用sync包。
WaitGroup
var wg sync.WaitGroup
func worker(id int) {
defer wg.Done()
fmt.Printf("Worker %d 完成\n", id)
}
func main() {
for i := 0; i < 5; i++ {
wg.Add(1)
go worker(i)
}
wg.Wait() // 等待所有goroutine完成
}Mutex
var (
counter int
mu sync.Mutex
)
func increment() {
mu.Lock()
defer mu.Unlock()
counter++
}Once
var once sync.Once
func setup() {
once.Do(func() {
fmt.Println("只执行一次")
})
}Context
Context用于控制goroutine的生命周期和取消操作。
func worker(ctx context.Context, id int) {
for {
select {
case <-ctx.Done():
fmt.Printf("Worker %d 被取消\n", id)
return
default:
// 执行工作
}
}
}
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
go worker(ctx, 1)
time.Sleep(3 * time.Second)
}最佳实践
- 优先使用channel:channel是Go并发编程的首选方式
- 避免共享状态:减少锁的使用,提高性能
- 合理使用缓冲:根据场景选择缓冲或非缓冲channel
- 及时关闭channel:使用defer确保资源释放
- 使用context控制生命周期:优雅地取消goroutine
总结
Go语言的并发模型简洁而强大,通过goroutine和channel可以轻松实现高效的并发程序。掌握这些概念后,你就能充分利用Go语言的并发优势了。