摘要:在 Go 语言中,多线程主要通过Goroutine和Channel实现。Go 的并发模型基于CSP(Communicating Sequential Processes)理论,强调通过通信共享内存,而非通过共享内存进行通信。以下是 Go 多线程的核心概念和实践
在 Go 语言中,多线程主要通过 Goroutine 和 Channel 实现。Go 的并发模型基于 CSP(Communicating Sequential Processes) 理论,强调通过通信共享内存,而非通过共享内存进行通信。以下是 Go 多线程的核心概念和实践:
1. Goroutine
轻量级线程:Goroutine 是 Go 运行时管理的轻量级线程,创建和切换开销极小(通常几 KB 的栈内存)。启动方式:使用 go 关键字即可启动一个 Goroutine。go
go func {
fmt.Println("Hello from Goroutine!")
}
2. 同步与通信
(1) Channel(通道)
用途:Goroutine 之间通过 Channel 传递数据,避免共享内存的竞态问题。类型:无缓冲通道:同步通信,发送和接收必须同时就绪。go
ch := make(chan int)
go func { ch
value :=
有缓冲通道:异步通信,缓冲区未满时发送不阻塞。go
复制
ch := make(chan int, 3)
ch
ch
(2) WaitGroup
用途:等待一组 Goroutine 完成。go
var wg sync.WaitGroup
for i := 0; i
wg.Add(1)
go func(i int) {
defer wg.Done
fmt.Println(i)
}(i)
}
wg.Wait
(3) Mutex(互斥锁)
用途:保护共享资源,避免数据竞争。go
var counter int
var mu sync.Mutex
for i := 0; i
go func {
mu.Lock
counter++
mu.Unlock
}
}
3. 常见并发模式
(1) Worker Pool
使用有缓冲 Channel 分发任务给一组 Goroutine。go
jobs := make(chan int, 100)
results := make(chan int, 100)
// 启动 3 个 Worker
for w := 1; w
go func(id int) {
for job := range jobs {
results
}
}(w)
}
// 分发任务
for i := 1; i
jobs
}
close(jobs)
// 收集结果
for i := 1; i
fmt.Println(
}
(2) Select
监听多个 Channel 的事件,处理超时或优先级。go
select {
case msg1 :=
fmt.Println(msg1)
case msg2 :=
fmt.Println(msg2)
case
fmt.Println("Timeout")
}
(3) Context
管理 Goroutine 的生命周期(取消、超时等)。go
ctx, cancel := context.WithTimeout(context.Background, 2*time.Second)
defer cancel
go func(ctx context.Context) {
select {
case
fmt.Println("Cancelled")
return
}
}(ctx)
4. 避免竞态条件
使用 go run -race main.go 检测数据竞争。优先使用 Channel 或 Mutex 保护共享资源。5. 注意事项
Goroutine 泄漏:确保 Goroutine 能正常退出(如通过 context 或关闭 Channel)。闭包陷阱:在循环中启动 Goroutine 时,通过参数传递循环变量:go
for i := 0; i
go func(x int) { // 正确做法:传递参数
fmt.Println(x)
}(i)
}
示例:并发 HTTP 请求
go
func fetch(url string, ch chan
start := time.Now
resp, err := http.Get(url)
if err != nil {
ch
return
}
secs := time.Since(start).Seconds
ch
}
func main {
urls := string{"https://google.com", "https://github.com"}
ch := make(chan string)
for _, url := range urls {
go fetch(url, ch)
}
for range urls {
fmt.Println(
}
}
Go 的并发模型简洁高效,但需谨慎处理同步和资源竞争问题。通过 Goroutine 和 Channel 的组合,可以轻松构建高并发的程序。
来源:老客数据一点号