Goroutine
外观
Goroutine是Go语言中实现并发编程的轻量级线程,由Go运行时管理。与操作系统线程相比,goroutine的创建和切换开销极小,使得开发者可以轻松创建成千上万的并发任务。
概述[编辑 | 编辑源代码]
Goroutine具有以下核心特性:
- 轻量级 - 初始栈大小仅2KB(可动态扩容)
- 低成本 - 创建和调度由Go运行时管理,不直接依赖OS线程
- 通信机制 - 通过channel实现安全的goroutine间通信
- 调度模型 - 采用M:N调度模型(M个goroutine映射到N个OS线程)
基本用法[编辑 | 编辑源代码]
使用go
关键字即可启动goroutine:
package main
import (
"fmt"
"time"
)
func say(s string) {
for i := 0; i < 3; i++ {
time.Sleep(100 * time.Millisecond)
fmt.Println(s)
}
}
func main() {
go say("world") // 启动goroutine
say("hello") // 主goroutine
}
输出示例:
hello world hello world hello world
调度原理[编辑 | 编辑源代码]
Go运行时使用GMP调度模型:
- G (Goroutine):待执行的任务
- M (Machine):操作系统线程
- P (Processor):调度上下文,包含本地运行队列
同步机制[编辑 | 编辑源代码]
Channel通信[编辑 | 编辑源代码]
channel是goroutine间通信的主要方式:
func worker(done chan bool) {
fmt.Print("working...")
time.Sleep(time.Second)
done <- true // 发送完成信号
}
func main() {
done := make(chan bool)
go worker(done)
<-done // 阻塞等待结果
}
WaitGroup同步[编辑 | 编辑源代码]
sync.WaitGroup
用于等待一组goroutine完成:
var wg sync.WaitGroup
func worker(id int) {
defer wg.Done()
fmt.Printf("Worker %d starting\n", id)
time.Sleep(time.Second)
}
func main() {
for i := 1; i <= 5; i++ {
wg.Add(1)
go worker(i)
}
wg.Wait() // 等待所有worker完成
}
最佳实践[编辑 | 编辑源代码]
1. 避免goroutine泄漏(确保所有goroutine都能退出)
2. 使用带缓冲的channel处理生产-消费模式
3. 限制并发数量(如使用semaphore模式)
4. 优先使用context
处理取消和超时
性能特点[编辑 | 编辑源代码]
对比传统线程:
特性 | Goroutine | OS线程 |
---|---|---|
创建开销 | ~2-4µs | ~1ms |
内存占用 | 初始2KB | 默认1-8MB |
切换成本 | ~200ns | ~1µs |
实际应用[编辑 | 编辑源代码]
Web服务器[编辑 | 编辑源代码]
处理HTTP请求的典型模式:
func handleRequest(w http.ResponseWriter, r *http.Request) {
go processRequest(r) // 异步处理
w.Write([]byte("请求已接收"))
}
并行计算[编辑 | 编辑源代码]
使用worker池处理任务:
func worker(id int, jobs <-chan int, results chan<- int) {
for j := range jobs {
results <- j * 2 // 处理任务
}
}
func main() {
jobs := make(chan int, 100)
results := make(chan int, 100)
// 启动3个worker
for w := 1; w <= 3; w++ {
go worker(w, jobs, results)
}
// 发送任务
for j := 1; j <= 9; j++ {
jobs <- j
}
close(jobs)
// 收集结果
for a := 1; a <= 9; a++ {
<-results
}
}