在 Go (Golang) 中,channel
和 mutex
是两种实现并发控制的常用工具,它们的设计理念和使用场景有明显差异。下面对比两者,并分析适用场景:
特性 | Channel | Mutex |
---|---|---|
类型 | 通信机制 | 同步原语 |
原理 | 通过消息传递共享内存 | 通过加锁保护共享内存 |
是否阻塞 | 可以阻塞(读/写操作) | 阻塞(当锁被持有时) |
通信目的 | 协程间数据传递和同步 | 数据访问控制 |
内置语法支持 |
|
|
channel
的场景channel 是基于 Go 的通过通信来同步而非共享内存(Do not communicate by sharing memory; share memory by communicating) 的理念设计的。Go 通过 channel 传递数据,从而实现协程间的通信和同步
示例:
func worker(id int, jobs <-chan int, results chan<- int) {
for j := range jobs {
results <- j * 2
}
}
mutex
的场景示例:
var mu sync.Mutex
var count int
func increment() {
mu.Lock()
count++
mu.Unlock()
}
比较项 | Channel | Mutex |
---|---|---|
易用性 | 更抽象,易于表达高层并发逻辑 | 简单直观,适合低层并发控制 |
性能 | 略低(有调度开销) | 高(加锁原子操作,效率更高) |
死锁风险 | 较低(设计良好的管道机制) | 较高(不当使用容易死锁或产生竞争条件) |
可读性 | 高(表达的是通信和意图) | 低(容易隐藏同步意图) |
场景 | 建议使用 |
---|---|
并发间通信 / 控制流 | Channel |
保护共享资源(如 map、计数器) | Mutex |
高性能要求 / 简单同步 | Mutex |
多 worker 聚合结果 / pipeline 模式 | Channel |
在 Go 实际开发中,我们也可以混合使用这两种机制。例如,用 channel 控制 worker 流程、用 mutex 保证数据安全更新。
下面是一个 Go 项目示例,结合使用了 channel 和 mutex,模拟了一个并发处理系统:
我们实现一个简单的并发网页爬虫:
sync.Mutex
安全地将结果写入共享 map。package main
import (
"fmt"
"net/http"
"sync"
"time"
)
var (
results = make(map[string]int)
mu sync.Mutex
)
func fetch(url string, wg *sync.WaitGroup, jobs <-chan string) {
defer wg.Done()
for u := range jobs {
resp, err := http.Get(u)
if err != nil {
fmt.Println("Error fetching:", u)
continue
}
// 保护共享资源 map
mu.Lock()
results[u] = resp.StatusCode
mu.Unlock()
resp.Body.Close()
}
}
func main() {
urls := []string{
"https://example.com",
"https://golang.org",
"https://openai.com",
"https://github.com",
}
const workerCount = 3
jobs := make(chan string, len(urls))
var wg sync.WaitGroup
// 启动多个 worker 协程
for i := 0; i < workerCount; i++ {
wg.Add(1)
go fetch("worker", &wg, jobs)
}
// 向 channel 中发送任务
for _, url := range urls {
jobs <- url
}
close(jobs)
// 等待所有任务完成
wg.Wait()
// 打印结果
fmt.Println("\nFetch Results:")
for url, code := range results {
fmt.Printf("%s -> %d\n", url, code)
}
}
组件 | 用途 |
---|---|
| 控制 worker 的任务分发 |
| 确保对共享 map 的并发写安全 |
| 等待所有协程完成处理 |
results
这个共享 map 的并发写操作不会造成竞态。原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。