Go语言并发编程完全指南
目录
1. 并发概述
1.1 并发vs并行
go
// 并发(Concurrency): 同时处理多个任务的能力
// - 在单核CPU上,通过时间片轮转
// - 任务交替执行,看起来像同时进行
// - 关注的是结构和设计
// 并行(Parallelism): 同时执行多个任务的能力
// - 在多核CPU上,真正的同时执行
// - 多个任务在不同的CPU核心上运行
// - 关注的是执行效率
// 比喻:
// 并发:一个咖啡师同时处理多个订单(接单、制作、交付交替进行)
// 并行:多个咖啡师各自处理不同的订单(真正同时进行)
1.2 Go的并发模型
Go采用CSP(Communicating Sequential Processes)模型:
go
// CSP核心理念:
// "不要通过共享内存来通信,而应该通过通信来共享内存"
// Don't communicate by sharing memory; share memory by communicating.
// 传统方式:共享内存 + 锁
var counter int
var mu sync.Mutex
func increment() {
mu.Lock()
counter++
mu.Unlock()
}
// Go方式:通过channel通信
func worker(ch chan int) {
for val := range ch {
// 处理数据
fmt.Println(val)
}
}
ch := make(chan int)
go worker(ch)
ch <- 42 // 发送数据
1.3 并发的优势和挑战
go
// ✅ 并发的优势
// 1. 提高程序响应性
// 2. 更好地利用多核CPU
// 3. 处理I/O密集型任务更高效
// 4. 简化某些问题的解决方案
// ⚠️ 并发的挑战
// 1. 数据竞争(Race Condition)
// 2. 死锁(Deadlock)
// 3. 活锁(Livelock)
// 4. 资源耗尽
// 检测数据竞争
// go run -race main.go
// go test -race
1.4 并发编程的基本原则
go
// 1. 避免共享状态
// ✅ 好:通过channel传递数据
func processData(data chan string) {
for d := range data {
// 处理d,无需担心其他goroutine
}
}
// 2. 最小化临界区
// ✅ 好:锁的范围尽可能小
func (c *Counter) Increment() {
c.mu.Lock()
c.value++ // 只保护需要的部分
c.mu.Unlock()
}
// 3. 使用正确的同步原语
// - Channel: 用于数据传递和同步
// - Mutex: 用于保护共享状态
// - WaitGroup: 用于等待goroutine完成
// - Context: 用于取消和超时控制
// 4. 避免goroutine泄漏
// ✅ 好:确保goroutine能够退出
func worker(ctx context.Context, data chan int) {
for {
select {
case d := <-data:
// 处理数据
case <-ctx.Done():
return // 收到取消信号,退出
}
}
}
2. Goroutine
2.1 创建和使用Goroutine
go
package main
import (
"fmt"
"time"
)
// 普通函数
func sayHello() {
fmt.Println("Hello from goroutine")
}
func main() {
// 方式1:启动命名函数
go sayHello()
// 方式2:启动匿名函数
go func() {
fmt.Println("Anonymous goroutine")
}()
// 方式3:带参数的goroutine
go func(msg string) {
fmt.Println(msg)
}("Hello with parameter")
// 主goroutine等待(否则程序会立即退出)
time.Sleep(time.Second)
}
2.2 Goroutine的生命周期
go
import (
"fmt"
"runtime"
"sync"
)
func main() {
// 查看当前goroutine数量
fmt.Println("Goroutines:", runtime.NumGoroutine()) // 1
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
fmt.Printf("Goroutine %d started\n", id)
time.Sleep(time.Millisecond * 100)
fmt.Printf("Goroutine %d finished\n", id)
}(i)
}
fmt.Println("Goroutines:", runtime.NumGoroutine()) // 11 (主 + 10个worker)
wg.Wait() // 等待所有goroutine完成
fmt.Println("All goroutines finished")
fmt.Println("Goroutines:", runtime.NumGoroutine()) // 1
}
2.3 Goroutine调度
go
import "runtime"
func main() {
// 获取CPU核心数
numCPU := runtime.NumCPU()
fmt.Println("CPU cores:", numCPU)
// 设置最大可同时使用的CPU核心数
runtime.GOMAXPROCS(numCPU)
// 主动让出CPU时间片
go func() {
for i := 0; i < 10; i++ {
fmt.Println("Goroutine 1:", i)
runtime.Gosched() // 让出CPU
}
}()
go func() {
for i := 0; i < 10; i++ {
fmt.Println("Goroutine 2:", i)
runtime.Gosched()
}
}()
time.Sleep(time.Second)
}
2.4 Goroutine通信模式
go
// 1. 单向数据流
func producer(ch chan<- int) { // 只写channel
for i := 0; i < 5; i++ {
ch <- i
}
close(ch)
}
func consumer(ch <-chan int) { // 只读channel
for val := range ch {
fmt.Println("Received:", val)
}
}
func main() {
ch := make(chan int)
go producer(ch)
consumer(ch)
}
// 2. 扇出模式(Fan-out): 一个生产者,多个消费者
func fanOut() {
jobs := make(chan int, 100)
results := make(chan int, 100)
// 生产者
go func() {
for i := 0; i < 100; i++ {
jobs <- i
}
close(jobs)
}()
// 多个worker
var wg sync.WaitGroup
for w := 0; w < 3; w++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
for job := range jobs {
results <- job * 2
}
}(w)
}
// 关闭结果channel
go func() {
wg.Wait()
close(results)
}()
// 收集结果
for result := range results {
fmt.Println(result)
}
}
// 3. 扇入模式(Fan-in): 多个生产者,一个消费者
func fanIn(inputs ...<-chan int) <-chan int {
out := make(chan int)
var wg sync.WaitGroup
// 为每个input启动一个goroutine
for _, input := range inputs {
wg.Add(1)
go func(ch <-chan int) {
defer wg.Done()
for val := range ch {
out <- val
}
}(input)
}
// 等待所有输入完成后关闭输出
go func() {
wg.Wait()
close(out)
}()
return out
}
2.5 Goroutine错误处理
go
// 使用channel传递错误
func worker(id int) (int, error) {
if id < 0 {
return 0, fmt.Errorf("invalid id: %d", id)
}
return id * 2, nil
}
type Result struct {
Value int
Err error
}
func main() {
jobs := []int{1, 2, -3, 4, 5}
results := make(chan Result, len(jobs))
// 启动workers
for _, job := range jobs {
go func(j int) {
val, err := worker(j)
results <- Result{Value: val, Err: err}
}(job)
}
// 收集结果
for i := 0; i < len(jobs); i++ {
result := <-results
if result.Err != nil {
fmt.Println("Error:", result.Err)
} else {
fmt.Println("Result:", result.Value)
}
}
}
// 使用errgroup
import "golang.org/x/sync/errgroup"
func processWithErrGroup() error {
g := new(errgroup.Group)
// 添加多个任务
for i := 0; i < 5; i++ {
i := i // 捕获循环变量
g.Go(func() error {
if i == 3 {
return fmt.Errorf("task %d failed", i)
}
fmt.Printf("Task %d completed\n", i)
return nil
})
}
// 等待所有任务完成,返回第一个错误
return g.Wait()
}
2.6 Goroutine泄漏防范
go
// ❌ 常见的goroutine泄漏
// 1. Channel永远阻塞
func leak1() {
ch := make(chan int)
go func() {
val := <-ch // 永远阻塞,goroutine泄漏
fmt.Println(val)
}()
// 忘记发送数据或关闭channel
}
// 2. 死循环没有退出条件
func leak2() {
go func() {
for {
// 永远运行,无法退出
doSomething()
}
}()
}
// ✅ 正确的做法
// 1. 使用context控制生命周期
func worker(ctx context.Context) {
for {
select {
case <-ctx.Done():
return // 收到取消信号,退出
default:
doWork()
}
}
}
// 2. 使用done channel
func workerWithDone(done <-chan struct{}) {
for {
select {
case <-done:
return
default:
doWork()
}
}
}
// 3. 使用带缓冲的channel避免阻塞
func processRequest(req Request) Response {
// 使用带缓冲的channel
ch := make(chan Response, 1)
go func() {
ch <- handleRequest(req)
}()
select {
case resp := <-ch:
return resp
case <-time.After(time.Second):
return Response{Error: "timeout"}
// goroutine会完成并发送到channel,不会泄漏
}
}
3. Channel
3.1 Channel基础
go
// 创建channel
ch1 := make(chan int) // 无缓冲channel
ch2 := make(chan int, 10) // 带缓冲channel
ch3 := make(chan string, 5) // 字符串channel
// 发送和接收
ch1 <- 42 // 发送值到channel
value := <-ch1 // 从channel接收值
// 关闭channel
close(ch1)
// 检查channel是否关闭
value, ok := <-ch1
if !ok {
fmt.Println("Channel closed")
}
// 单向channel
var sendOnly chan<- int = ch1 // 只能发送
var recvOnly <-chan int = ch1 // 只能接收
3.2 无缓冲vs有缓冲Channel
go
// 无缓冲channel: 同步通信
func unbuffered() {
ch := make(chan int)
go func() {
fmt.Println("Sending...")
ch <- 42 // 阻塞,直到有接收者
fmt.Println("Sent!")
}()
time.Sleep(time.Second)
fmt.Println("Receiving...")
val := <-ch // 阻塞,直到有发送者
fmt.Println("Received:", val)
}
// 输出:
// Sending...
// (1秒后)
// Receiving...
// Sent!
// Received: 42
// 有缓冲channel: 异步通信
func buffered() {
ch := make(chan int, 2)
ch <- 1 // 不阻塞
ch <- 2 // 不阻塞
// ch <- 3 // 阻塞,缓冲区满
fmt.Println(<-ch) // 1
fmt.Println(<-ch) // 2
// 查看channel状态
fmt.Println("Length:", len(ch)) // 0
fmt.Println("Capacity:", cap(ch)) // 2
}
3.3 Channel使用模式
go
// 1. 信号通知
func signalPattern() {
done := make(chan struct{}) // 空struct不占内存
go func() {
fmt.Println("Working...")
time.Sleep(time.Second)
close(done) // 发送信号
}()
<-done // 等待信号
fmt.Println("Done!")
}
// 2. 管道模式(Pipeline)
func pipeline() {
// 阶段1: 生成数据
gen := func(nums ...int) <-chan int {
out := make(chan int)
go func() {
for _, n := range nums {
out <- n
}
close(out)
}()
return out
}
// 阶段2: 平方
sq := func(in <-chan int) <-chan int {
out := make(chan int)
go func() {
for n := range in {
out <- n * n
}
close(out)
}()
return out
}
// 阶段3: 求和
sum := func(in <-chan int) int {
total := 0
for n := range in {
total += n
}
return total
}
// 连接管道
nums := gen(1, 2, 3, 4)
squares := sq(nums)
result := sum(squares)
fmt.Println(result) // 30 (1+4+9+16)
}
// 3. 超时模式
func timeoutPattern() {
ch := make(chan string, 1)
go func() {
time.Sleep(2 * time.Second)
ch <- "result"
}()
select {
case res := <-ch:
fmt.Println(res)
case <-time.After(1 * time.Second):
fmt.Println("Timeout!")
}
}
// 4. Future模式
type Future struct {
result chan string
}
func (f *Future) Get() string {
return <-f.result
}
func asyncCall() *Future {
future := &Future{
result: make(chan string, 1),
}
go func() {
// 模拟耗时操作
time.Sleep(time.Second)
future.result <- "Result"
}()
return future
}
func futurePattern() {
future := asyncCall()
// 做其他事情...
fmt.Println("Doing other work...")
// 需要结果时获取
result := future.Get()
fmt.Println(result)
}
// 5. 工作池模式
func workerPool() {
jobs := make(chan int, 100)
results := make(chan int, 100)
// 启动3个worker
for w := 1; w <= 3; w++ {
go func(id int) {
for job := range jobs {
fmt.Printf("Worker %d processing job %d\n", id, job)
results <- job * 2
}
}(w)
}
// 发送任务
for j := 1; j <= 9; j++ {
jobs <- j
}
close(jobs)
// 收集结果
for r := 1; r <= 9; r++ {
<-results
}
}
3.4 Channel的关闭和范围遍历
go
// 关闭channel的规则
func closeRules() {
ch := make(chan int, 3)
// ✅ 发送者负责关闭channel
go func() {
for i := 0; i < 5; i++ {
ch <- i
}
close(ch) // 发送完毕后关闭
}()
// ✅ 使用range遍历,自动处理关闭
for val := range ch {
fmt.Println(val)
}
// ❌ 向已关闭的channel发送会panic
// ch <- 10 // panic: send on closed channel
// ✅ 从已关闭的channel接收会立即返回零值
val, ok := <-ch
fmt.Println(val, ok) // 0 false
// ❌ 关闭已关闭的channel会panic
// close(ch) // panic: close of closed channel
// ❌ 关闭nil channel会panic
// var ch2 chan int
// close(ch2) // panic: close of nil channel
}
// 检查channel是否关闭
func checkClosed() {
ch := make(chan int, 1)
ch <- 42
close(ch)
// 方法1: 使用ok检查
if val, ok := <-ch; ok {
fmt.Println("Received:", val)
} else {
fmt.Println("Channel closed")
}
// 方法2: 使用range(推荐)
ch2 := make(chan int, 3)
go func() {
for i := 0; i < 3; i++ {
ch2 <- i
}
close(ch2)
}()
for val := range ch2 {
fmt.Println(val)
}
}
3.5 nil Channel的行为
go
func nilChannel() {
var ch chan int // nil channel
// ❌ 发送到nil channel永远阻塞
// ch <- 1 // 永久阻塞
// ❌ 从nil channel接收永远阻塞
// val := <-ch // 永久阻塞
// ✅ nil channel在select中很有用
var ch1, ch2 chan int
select {
case <-ch1:
// 永远不会执行
case <-ch2:
// 永远不会执行
default:
fmt.Println("No channel ready")
}
// 实际应用:延迟初始化
type Config struct {
once sync.Once
data map[string]string
}
func (c *Config) Load() {
c.once.Do(func() {
fmt.Println("Loading config...")
c.data = make(map[string]string)
// 从文件或数据库加载配置
c.data["key"] = "value"
})
}
func (c *Config) Get(key string) string {
c.Load() // 确保已加载
return c.data[key]
}
4.5 Cond(条件变量)
go
// Cond用于等待/通知机制
type Queue struct {
mu sync.Mutex
cond *sync.Cond
items []int
}
func NewQueue() *Queue {
q := &Queue{
items: make([]int, 0),
}
q.cond = sync.NewCond(&q.mu)
return q
}
func (q *Queue) Enqueue(item int) {
q.mu.Lock()
defer q.mu.Unlock()
q.items = append(q.items, item)
q.cond.Signal() // 唤醒一个等待的goroutine
// q.cond.Broadcast() // 唤醒所有等待的goroutine
}
func (q *Queue) Dequeue() int {
q.mu.Lock()
defer q.mu.Unlock()
for len(q.items) == 0 {
q.cond.Wait() // 等待信号
}
item := q.items[0]
q.items = q.items[1:]
return item
}
func condExample() {
queue := NewQueue()
// 消费者
go func() {
for i := 0; i < 10; i++ {
item := queue.Dequeue()
fmt.Println("Dequeued:", item)
}
}()
// 生产者
time.Sleep(time.Second)
for i := 0; i < 10; i++ {
queue.Enqueue(i)
time.Sleep(time.Millisecond * 100)
}
}
4.6 Map(并发安全的Map)
go
import "sync"
// sync.Map适用于读多写少的场景
func syncMapExample() {
var m sync.Map
// 存储
m.Store("key1", "value1")
m.Store("key2", "value2")
// 加载
if val, ok := m.Load("key1"); ok {
fmt.Println("Found:", val)
}
// 加载或存储(原子操作)
actual, loaded := m.LoadOrStore("key3", "value3")
fmt.Println("Actual:", actual, "Loaded:", loaded)
// 删除
m.Delete("key1")
// 遍历
m.Range(func(key, value interface{}) bool {
fmt.Printf("%s: %s\n", key, value)
return true // 返回false停止遍历
})
// 加载并删除
if val, ok := m.LoadAndDelete("key2"); ok {
fmt.Println("Deleted:", val)
}
}
// 自定义类型安全的并发Map
type SafeMap[K comparable, V any] struct {
mu sync.RWMutex
data map[K]V
}
func NewSafeMap[K comparable, V any]() *SafeMap[K, V] {
return &SafeMap[K, V]{
data: make(map[K]V),
}
}
func (m *SafeMap[K, V]) Set(key K, value V) {
m.mu.Lock()
defer m.mu.Unlock()
m.data[key] = value
}
func (m *SafeMap[K, V]) Get(key K) (V, bool) {
m.mu.RLock()
defer m.mu.RUnlock()
val, ok := m.data[key]
return val, ok
}
func (m *SafeMap[K, V]) Delete(key K) {
m.mu.Lock()
defer m.mu.Unlock()
delete(m.data, key)
}
4.7 Pool(对象池)
go
import "sync"
// Pool用于复用临时对象,减少GC压力
func poolExample() {
// 创建对象池
pool := &sync.Pool{
New: func() interface{} {
fmt.Println("Creating new buffer")
return new(bytes.Buffer)
},
}
// 获取对象
buffer := pool.Get().(*bytes.Buffer)
buffer.WriteString("Hello, World!")
fmt.Println(buffer.String())
// 重置并归还
buffer.Reset()
pool.Put(buffer)
// 再次获取(可能是刚才归还的)
buffer2 := pool.Get().(*bytes.Buffer)
fmt.Println("Buffer empty:", buffer2.Len() == 0)
pool.Put(buffer2)
}
// 实际应用:HTTP响应缓存
var responsePool = sync.Pool{
New: func() interface{} {
return &Response{
Headers: make(map[string]string),
}
},
}
type Response struct {
Status int
Body string
Headers map[string]string
}
func handleRequest(req Request) *Response {
resp := responsePool.Get().(*Response)
// 使用response
resp.Status = 200
resp.Body = "OK"
return resp
}
func releaseResponse(resp *Response) {
// 重置状态
resp.Status = 0
resp.Body = ""
for k := range resp.Headers {
delete(resp.Headers, k)
}
responsePool.Put(resp)
}
4.8 Atomic(原子操作)
go
import "sync/atomic"
// 原子操作比Mutex更轻量
type AtomicCounter struct {
value int64
}
func (c *AtomicCounter) Increment() {
atomic.AddInt64(&c.value, 1)
}
func (c *AtomicCounter) Decrement() {
atomic.AddInt64(&c.value, -1)
}
func (c *AtomicCounter) Value() int64 {
return atomic.LoadInt64(&c.value)
}
func (c *AtomicCounter) Set(value int64) {
atomic.StoreInt64(&c.value, value)
}
func (c *AtomicCounter) CompareAndSwap(old, new int64) bool {
return atomic.CompareAndSwapInt64(&c.value, old, new)
}
func atomicExample() {
counter := &AtomicCounter{}
var wg sync.WaitGroup
// 并发增加
for i := 0; i < 1000; i++ {
wg.Add(1)
go func() {
defer wg.Done()
counter.Increment()
}()
}
wg.Wait()
fmt.Println("Final value:", counter.Value()) // 1000
}
// 原子操作的其他类型
func atomicTypes() {
// int32/int64
var i32 int32
atomic.AddInt32(&i32, 1)
var i64 int64
atomic.AddInt64(&i64, 1)
// uint32/uint64
var u32 uint32
atomic.AddUint32(&u32, 1)
// uintptr
var ptr uintptr
atomic.AddUintptr(&ptr, 1)
// Value (任意类型)
var v atomic.Value
v.Store("hello")
fmt.Println(v.Load()) // hello
}
// 原子操作的应用:无锁队列
type LockFreeQueue struct {
head unsafe.Pointer
tail unsafe.Pointer
}
type node struct {
value interface{}
next unsafe.Pointer
}
func NewLockFreeQueue() *LockFreeQueue {
n := unsafe.Pointer(&node{})
return &LockFreeQueue{
head: n,
tail: n,
}
}
func (q *LockFreeQueue) Enqueue(value interface{}) {
n := &node{value: value}
for {
tail := atomic.LoadPointer(&q.tail)
next := atomic.LoadPointer(&(*node)(tail).next)
if tail == atomic.LoadPointer(&q.tail) {
if next == nil {
if atomic.CompareAndSwapPointer(&(*node)(tail).next, next, unsafe.Pointer(n)) {
atomic.CompareAndSwapPointer(&q.tail, tail, unsafe.Pointer(n))
return
}
} else {
atomic.CompareAndSwapPointer(&q.tail, tail, next)
}
}
}
}
5. Select
5.1 Select基础
go
// select用于多路复用channel操作
func selectBasic() {
ch1 := make(chan string)
ch2 := make(chan string)
go func() {
time.Sleep(1 * time.Second)
ch1 <- "from ch1"
}()
go func() {
time.Sleep(2 * time.Second)
ch2 <- "from ch2"
}()
// select会执行第一个就绪的case
select {
case msg1 := <-ch1:
fmt.Println(msg1)
case msg2 := <-ch2:
fmt.Println(msg2)
}
// 输出: from ch1 (因为ch1先就绪)
}
5.2 Select with Default
go
// default case立即执行(非阻塞)
func selectDefault() {
ch := make(chan int, 1)
// 非阻塞发送
select {
case ch <- 42:
fmt.Println("Sent")
default:
fmt.Println("Channel full")
}
// 非阻塞接收
select {
case val := <-ch:
fmt.Println("Received:", val)
default:
fmt.Println("Channel empty")
}
}
// 实际应用:非阻塞检查
func tryReceive(ch <-chan int) (int, bool) {
select {
case val := <-ch:
return val, true
default:
return 0, false
}
}
func trySend(ch chan<- int, val int) bool {
select {
case ch <- val:
return true
default:
return false
}
}
5.3 Select超时模式
go
// 超时控制
func selectTimeout() {
ch := make(chan string)
go func() {
time.Sleep(2 * time.Second)
ch <- "result"
}()
select {
case res := <-ch:
fmt.Println("Got:", res)
case <-time.After(1 * time.Second):
fmt.Println("Timeout!")
}
}
// 心跳检测
func heartbeat() {
heartbeatCh := make(chan struct{})
// 模拟心跳
go func() {
ticker := time.NewTicker(500 * time.Millisecond)
defer ticker.Stop()
for range ticker.C {
heartbeatCh <- struct{}{}
}
}()
// 监控心跳
timeout := time.After(2 * time.Second)
for {
select {
case <-heartbeatCh:
fmt.Println("Heartbeat received")
case <-timeout:
fmt.Println("Heartbeat timeout!")
return
}
}
}
5.4 Select多通道监听
go
// 同时监听多个channel
func selectMultiple() {
done := make(chan struct{})
ch1 := make(chan int)
ch2 := make(chan string)
ch3 := make(chan bool)
// 启动多个goroutine
go func() {
for i := 0; i < 5; i++ {
ch1 <- i
time.Sleep(100 * time.Millisecond)
}
}()
go func() {
for i := 0; i < 3; i++ {
ch2 <- fmt.Sprintf("msg%d", i)
time.Sleep(150 * time.Millisecond)
}
}()
go func() {
time.Sleep(500 * time.Millisecond)
ch3 <- true
}()
// 监听所有channel
go func() {
time.Sleep(1 * time.Second)
close(done)
}()
for {
select {
case num := <-ch1:
fmt.Println("Int:", num)
case msg := <-ch2:
fmt.Println("String:", msg)
case flag := <-ch3:
fmt.Println("Bool:", flag)
case <-done:
fmt.Println("Done!")
return
}
}
}
5.5 Select动态case
go
// 动态启用/禁用case
func selectDynamic() {
ch1 := make(chan int)
ch2 := make(chan int)
// 发送数据
go func() {
for i := 0; i < 10; i++ {
ch1 <- i
time.Sleep(100 * time.Millisecond)
}
close(ch1)
}()
go func() {
for i := 0; i < 10; i++ {
ch2 <- i * 10
time.Sleep(100 * time.Millisecond)
}
close(ch2)
}()
// 动态选择
for ch1 != nil || ch2 != nil {
select {
case val, ok := <-ch1:
if !ok {
ch1 = nil // 禁用ch1的case
fmt.Println("ch1 closed")
} else {
fmt.Println("ch1:", val)
}
case val, ok := <-ch2:
if !ok {
ch2 = nil // 禁用ch2的case
fmt.Println("ch2 closed")
} else {
fmt.Println("ch2:", val)
}
}
}
}
5.6 Select优先级
go
// select的case是随机选择的,没有优先级
// 如果需要优先级,需要手动实现
func selectPriority() {
highPriority := make(chan int)
lowPriority := make(chan int)
done := make(chan struct{})
go func() {
time.Sleep(500 * time.Millisecond)
close(done)
}()
go func() {
for i := 0; i < 5; i++ {
highPriority <- i
time.Sleep(50 * time.Millisecond)
}
}()
go func() {
for i := 0; i < 10; i++ {
lowPriority <- i * 10
time.Sleep(50 * time.Millisecond)
}
}()
for {
select {
case <-done:
return
case val := <-highPriority:
fmt.Println("High:", val)
default:
// 只有高优先级channel没有数据时才检查低优先级
select {
case val := <-lowPriority:
fmt.Println("Low:", val)
default:
time.Sleep(10 * time.Millisecond)
}
}
}
}
5.7 Select常见模式
go
// 1. 退出模式
func quitPattern() {
quit := make(chan struct{})
data := make(chan int)
go func() {
for {
select {
case d := <-data:
fmt.Println("Processing:", d)
case <-quit:
fmt.Println("Quitting...")
return
}
}
}()
for i := 0; i < 5; i++ {
data <- i
}
close(quit)
time.Sleep(100 * time.Millisecond)
}
// 2. 超时重试模式
func timeoutRetry() error {
maxRetries := 3
timeout := time.Second
for i := 0; i < maxRetries; i++ {
result := make(chan error, 1)
go func() {
result <- doWork()
}()
select {
case err := <-result:
if err == nil {
return nil
}
fmt.Printf("Attempt %d failed: %v\n", i+1, err)
case <-time.After(timeout):
fmt.Printf("Attempt %d timeout\n", i+1)
}
timeout *= 2 // 指数退避
}
return fmt.Errorf("all retries failed")
}
// 3. 合并多个channel
func mergeChannels(channels ...<-chan int) <-chan int {
out := make(chan int)
var wg sync.WaitGroup
// 为每个channel启动一个goroutine
for _, ch := range channels {
wg.Add(1)
go func(c <-chan int) {
defer wg.Done()
for val := range c {
out <- val
}
}(ch)
}
// 等待所有channel关闭后关闭输出
go func() {
wg.Wait()
close(out)
}()
return out
}
// 4. 取第一个响应
func firstResponse() string {
ch1 := query("server1")
ch2 := query("server2")
ch3 := query("server3")
select {
case resp := <-ch1:
return resp
case resp := <-ch2:
return resp
case resp := <-ch3:
return resp
case <-time.After(time.Second):
return "timeout"
}
}
func query(server string) <-chan string {
ch := make(chan string, 1)
go func() {
time.Sleep(time.Duration(rand.Intn(500)) * time.Millisecond)
ch <- fmt.Sprintf("response from %s", server)
}()
return ch
}
6. Context
6.1 Context基础
go
import "context"
// Context用于传递请求范围的值、取消信号、截止时间
func contextBasic() {
// 1. 创建根context
ctx := context.Background() // 永不取消
ctx = context.TODO() // 待定,不确定用哪个
// 2. WithCancel: 可取消的context
ctx, cancel := context.WithCancel(context.Background())
defer cancel() // 确保资源释放
go func() {
<-ctx.Done()
fmt.Println("Context cancelled:", ctx.Err())
}()
time.Sleep(100 * time.Millisecond)
cancel() // 取消context
time.Sleep(100 * time.Millisecond)
}
6.2 WithTimeout和WithDeadline
go
// WithTimeout: 超时自动取消
func contextTimeout() {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
select {
case <-time.After(3 * time.Second):
fmt.Println("Operation completed")
case <-ctx.Done():
fmt.Println("Timeout:", ctx.Err()) // context deadline exceeded
}
}
// WithDeadline: 指定截止时间
func contextDeadline() {
deadline := time.Now().Add(2 * time.Second)
ctx, cancel := context.WithDeadline(context.Background(), deadline)
defer cancel()
select {
case <-time.After(3 * time.Second):
fmt.Println("Operation completed")
case <-ctx.Done():
fmt.Println("Deadline exceeded:", ctx.Err())
}
}
// 实际应用:HTTP请求超时
func fetchWithTimeout(url string, timeout time.Duration) error {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
if err != nil {
return err
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
// 处理响应...
return nil
}
6.3 WithValue传递值
go
type contextKey string
const (
userIDKey contextKey = "userID"
requestIDKey contextKey = "requestID"
)
// WithValue: 传递请求范围的值
func contextValue() {
// 设置值
ctx := context.WithValue(context.Background(), userIDKey, "user123")
ctx = context.WithValue(ctx, requestIDKey, "req456")
// 获取值
processRequest(ctx)
}
func processRequest(ctx context.Context) {
userID, ok := ctx.Value(userIDKey).(string)
if ok {
fmt.Println("User ID:", userID)
}
requestID := ctx.Value(requestIDKey)
fmt.Println("Request ID:", requestID)
}
// ⚠️ Context.Value使用注意事项
// 1. 只用于请求范围的数据
// 2. 不要存储可选参数
// 3. 类型安全:使用自定义类型作为key
// 4. 不要存储大量数据
// ✅ 好的用法:传递用户身份、请求ID、认证token
// ❌ 不好的用法:传递函数参数、配置选项
6.4 Context传播
go
// Context应该在调用链中传递
func operation(ctx context.Context) error {
// 检查是否已取消
if err := ctx.Err(); err != nil {
return err
}
// 继续传递context
return subOperation(ctx)
}
func subOperation(ctx context.Context) error {
select {
case <-time.After(time.Second):
// 模拟工作
return nil
case <-ctx.Done():
return ctx.Err()
}
}
// 实际示例:数据库查询
func queryDatabase(ctx context.Context, query string) error {
// 创建带超时的子context
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
// 执行查询
resultCh := make(chan error, 1)
go func() {
// 模拟数据库查询
time.Sleep(2 * time.Second)
resultCh <- nil
}()
select {
case err := <-resultCh:
return err
case <-ctx.Done():
return fmt.Errorf("query cancelled: %w", ctx.Err())
}
}
6.5 Context最佳实践
go
// 1. Context作为第一个参数
func Process(ctx context.Context, data string) error {
// ✅ 正确
}
func ProcessBad(data string, ctx context.Context) error {
// ❌ 错误:context应该是第一个参数
}
// 2. 不要存储Context
type Server struct {
ctx context.Context // ❌ 不要这样做
}
// ✅ 正确:在函数调用时传递
func (s *Server) HandleRequest(ctx context.Context) {}
// 3. Context链式传递
func handler(ctx context.Context) error {
// 创建子context
ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
defer cancel()
// 传递给下游
return process(ctx)
}
func process(ctx context.Context) error {
// 继续传递
return save(ctx)
}
func save(ctx context.Context) error {
select {
case <-time.After(time.Second):
return nil
case <-ctx.Done():
return ctx.Err()
}
}
// 4. 优雅关闭
func gracefulShutdown() {
ctx, cancel := context.WithCancel(context.Background())
// 启动服务
go func() {
server := &http.Server{Addr: ":8080"}
// 监听关闭信号
<-ctx.Done()
// 给服务5秒时间关闭
shutdownCtx, shutdownCancel := context.WithTimeout(
context.Background(),
5*time.Second,
)
defer shutdownCancel()
if err := server.Shutdown(shutdownCtx); err != nil {
log.Printf("Server shutdown error: %v", err)
}
}()
// 等待中断信号
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM)
<-sigCh
fmt.Println("Shutting down...")
cancel()
time.Sleep(6 * time.Second)
}
6.6 Context实战案例
go
// 案例1: 并发HTTP请求与超时控制
func fetchMultipleURLs(urls []string, timeout time.Duration) []string {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
resultCh := make(chan string, len(urls))
var wg sync.WaitGroup
for _, url := range urls {
wg.Add(1)
go func(u string) {
defer wg.Done()
req, _ := http.NewRequestWithContext(ctx, "GET", u, nil)
resp, err := http.DefaultClient.Do(req)
if err != nil {
resultCh <- fmt.Sprintf("%s: error - %v", u, err)
return
}
defer resp.Body.Close()
resultCh <- fmt.Sprintf("%s: status %d", u, resp.StatusCode)
}(url)
}
go func() {
wg.Wait()
close(resultCh)
}()
var results []string
for result := range resultCh {
results = append(results, result)
}
return results
}
// 案例2: 级联取消
func cascadingCancel() {
parentCtx, parentCancel := context.WithCancel(context.Background())
defer parentCancel()
// 子context 1
child1Ctx, child1Cancel := context.WithCancel(parentCtx)
defer child1Cancel()
// 子context 2
child2Ctx, child2Cancel := context.WithTimeout(parentCtx, 5*time.Second)
defer child2Cancel()
// 启动workers
go worker(child1Ctx, "Worker 1")
go worker(child2Ctx, "Worker 2")
time.Sleep(2 * time.Second)
parentCancel() // 取消父context,所有子context也被取消
time.Sleep(time.Second)
}
func worker(ctx context.Context, name string) {
for {
select {
case <-ctx.Done():
fmt.Printf("%s stopped: %v\n", name, ctx.Err())
return
case <-time.After(500 * time.Millisecond):
fmt.Printf("%s working...\n", name)
}
}
}
// 案例3: 数据库事务与Context
func transactionWithContext(ctx context.Context, db *sql.DB) error {
tx, err := db.BeginTx(ctx, nil)
if err != nil {
return err
}
defer tx.Rollback()
// 执行多个操作
if err := insertUser(ctx, tx, "Alice"); err != nil {
return err
}
if err := insertOrder(ctx, tx, 123); err != nil {
return err
}
// 提交事务
return tx.Commit()
}
func insertUser(ctx context.Context, tx *sql.Tx, name string) error {
_, err := tx.ExecContext(ctx, "INSERT INTO users (name) VALUES (?)", name)
return err
}
7. 定时器
7.1 Timer(一次性定时器)
go
import "time"
// Timer在指定时间后触发一次
func timerBasic() {
timer := time.NewTimer(2 * time.Second)
fmt.Println("Timer started")
<-timer.C // 等待定时器触发
fmt.Println("Timer fired!")
}
// 取消Timer
func timerCancel() {
timer := time.NewTimer(5 * time.Second)
go func() {
<-timer.C
fmt.Println("Timer fired")
}()
// 2秒后取消
time.Sleep(2 * time.Second)
if timer.Stop() {
fmt.Println("Timer cancelled")
}
}
// 重置Timer
func timerReset() {
timer := time.NewTimer(1 * time.Second)
go func() {
for {
<-timer.C
fmt.Println("Timer fired:", time.Now())
}
}()
time.Sleep(1500 * time.Millisecond)
timer.Reset(1 * time.Second) // 重置定时器
time.Sleep(2 * time.Second)
}
// After: 简化的Timer
func afterExample() {
select {
case <-time.After(1 * time.Second):
fmt.Println("Timeout!")
}
}
7.2 Ticker(周期性定时器)
go
// Ticker周期性触发
func tickerBasic() {
ticker := time.NewTicker(500 * time.Millisecond)
defer ticker.Stop() // 必须停止,否则泄漏
count := 0
for {
<-ticker.C
count++
fmt.Println("Tick", count)
if count >= 5 {
break
}
}
}
// Ticker与select
func tickerSelect() {
ticker := time.NewTicker(500 * time.Millisecond)
defer ticker.Stop()
done := make(chan bool)
go func() {
time.Sleep(3 * time.Second)
done <- true
}()
for {
select {
case <-ticker.C:
fmt.Println("Tick at", time.Now())
case <-done:
fmt.Println("Done!")
return
}
}
}
// Tick: 简化的Ticker(不能停止)
func tickExample() {
c := time.Tick(1 * time.Second)
for i := 0; i < 3; i++ {
<-c
fmt.Println("Tick")
}
// 注意:无法停止,会导致goroutine泄漏
}
7.3 定时器应用场景
go
// 1. 心跳检测
func heartbeatMonitor() {
heartbeat := make(chan struct{})
// 模拟心跳发送
go func() {
ticker := time.NewTicker(1 * time.Second)
defer ticker.Stop()
for range ticker.C {
heartbeat <- struct{}{}
}
}()
// 监控心跳
ticker := time.NewTicker(3 * time.Second)
defer ticker.Stop()
for {
select {
case <-heartbeat:
fmt.Println("Heartbeat received")
case <-ticker.C:
fmt.Println("Heartbeat timeout!")
return
}
}
}
// 2. 限流器
type RateLimiter struct {
ticker *time.Ticker
bucket chan struct{}
}
func NewRateLimiter(rate int, burst int) *RateLimiter {
rl := &RateLimiter{
ticker: time.NewTicker(time.Second / time.Duration(rate)),
bucket: make(chan struct{}, burst),
}
// 初始填充
for i := 0; i < burst; i++ {
rl.bucket <- struct{}{}
}
// 定期补充令牌
go func() {
for range rl.ticker.C {
select {
case rl.bucket <- struct{}{}:
default:
}
}
}()
return rl
}
func (rl *RateLimiter) Allow() bool {
select {
case <-rl.bucket:
return true
default:
return false
}
}
func (rl *RateLimiter) Wait() {
<-rl.bucket
}
func (rl *RateLimiter) Stop() {
rl.ticker.Stop()
}
// 使用限流器
func rateLimiterExample() {
limiter := NewRateLimiter(2, 5) // 每秒2个请求,最大突发5个
defer limiter.Stop()
for i := 0; i < 10; i++ {
if limiter.Allow() {
fmt.Printf("Request %d: allowed\n", i)
} else {
fmt.Printf("Request %d: blocked\n", i)
}
time.Sleep(200 * time.Millisecond)
}
}
// 3. 超时重试
func retryWithTimeout(fn func() error, maxRetries int, timeout time.Duration) error {
timer := time.NewTimer(timeout)
defer timer.Stop()
for i := 0; i < maxRetries; i++ {
errCh := make(chan error, 1)
go func() {
errCh <- fn()
}()
select {
case err := <-errCh:
if err == nil {
return nil
}
fmt.Printf("Attempt %d failed: %v\n", i+1, err)
case <-timer.C:
return fmt.Errorf("timeout after %v", timeout)
}
// 等待后重试
time.Sleep(time.Second * time.Duration(i+1))
}
return fmt.Errorf("max retries exceeded")
}
// 4. 定时任务调度
type Scheduler struct {
tasks map[string]*time.Ticker
mu sync.Mutex
}
func NewScheduler() *Scheduler {
return &Scheduler{
tasks: make(map[string]*time.Ticker),
}
}
func (s *Scheduler) Schedule(name string, interval time.Duration, fn func()) {
s.mu.Lock()
defer s.mu.Unlock()
// 停止已存在的任务
if ticker, ok := s.tasks[name]; ok {
ticker.Stop()
}
// 创建新任务
ticker := time.NewTicker(interval)
s.tasks[name] = ticker
go func() {
for range ticker.C {
fn()
}
}()
}
func (s *Scheduler) Cancel(name string) {
s.mu.Lock()
defer s.mu.Unlock()
if ticker, ok := s.tasks[name]; ok {
ticker.Stop()
delete(s.tasks, name)
}
}
func (s *Scheduler) StopAll() {
s.mu.Lock()
defer s.mu.Unlock()
for _, ticker := range s.tasks {
ticker.Stop()
}
s.tasks = make(map[string]*time.Ticker)
}
// 使用调度器
func schedulerExample() {
scheduler := NewScheduler()
defer scheduler.StopAll()
// 每秒执行
scheduler.Schedule("task1", time.Second, func() {
fmt.Println("Task 1 executed at", time.Now())
})
// 每2秒执行
scheduler.Schedule("task2", 2*time.Second, func() {
fmt.Println("Task 2 executed at", time.Now())
})
time.Sleep(5 * time.Second)
scheduler.Cancel("task1")
time.Sleep(3 * time.Second)
}
// 5. 延迟队列
type DelayQueue struct {
items chan *delayedItem
}
type delayedItem struct {
value interface{}
delay time.Duration
}
func NewDelayQueue() *DelayQueue {
dq := &DelayQueue{
items: make(chan *delayedItem, 100),
}
go dq.process()
return dq
}
func (dq *DelayQueue) Push(value interface{}, delay time.Duration) {
dq.items <- &delayedItem{
value: value,
delay: delay,
}
}
func (dq *DelayQueue) process() {
for item := range dq.items {
go func(i *delayedItem) {
time.Sleep(i.delay)
fmt.Printf("Processing: %v\n", i.value)
}(item)
}
}
8. 协程池
8.1 简单的协程池
go
// 固定大小的worker池
type WorkerPool struct {
tasks chan func()
workers int
}
func NewWorkerPool(workers int) *WorkerPool {
pool := &WorkerPool{
tasks: make(chan func(), 100),
workers: workers,
}
pool.start()
return pool
}
func (p *WorkerPool) start() {
for i := 0; i < p.workers; i++ {
go func(workerID int) {
for task := range p.tasks {
fmt.Printf("Worker %d executing task\n", workerID)
task()
}
}(i)
}
}
func (p *WorkerPool) Submit(task func()) {
p.tasks <- task
}
func (p *WorkerPool) Close() {
close(p.tasks)
}
// 使用worker池
func workerPoolExample() {
pool := NewWorkerPool(3)
defer pool.Close()
for i := 0; i < 10; i++ {
id := i
pool.Submit(func() {
fmt.Printf("Task %d processing\n", id)
time.Sleep(time.Second)
})
}
time.Sleep(5 * time.Second)
}
8.2 带结果的协程池
go
type Task struct {
ID int
Job func() interface{}
}
type Result struct {
TaskID int
Value interface{}
Err error
}
type ResultPool struct {
tasks chan Task
results chan Result
workers int
wg sync.WaitGroup
}
func NewResultPool(workers int) *ResultPool {
pool := &ResultPool{
tasks: make(chan Task, 100),
results: make(chan Result, 100),
workers: workers,
}
for i := 0; i < workers; i++ {
pool.wg.Add(1)
go pool.worker()
}
return pool
}
func (p *ResultPool) worker() {
defer p.wg.Done()
for task := range p.tasks {
result := Result{TaskID: task.ID}
// 捕获panic
func() {
defer func() {
if r := recover(); r != nil {
result.Err = fmt.Errorf("panic: %v", r)
}
}()
result.Value = task.Job()
}()
p.results <- result
}
}
func (p *ResultPool) Submit(task Task) {
p.tasks <- task
}
func (p *ResultPool) Results() <-chan Result {
return p.results
}
func (p *ResultPool) Close() {
close(p.tasks)
p.wg.Wait()
close(p.results)
}
// 使用
func resultPoolExample() {
pool := NewResultPool(5)
// 提交任务
go func() {
for i := 0; i < 20; i++ {
id := i
pool.Submit(Task{
ID: id,
Job: func() interface{} {
time.Sleep(time.Millisecond * 100)
return id * 2
},
})
}
pool.Close()
}()
// 收集结果
for result := range pool.Results() {
if result.Err != nil {
fmt.Printf("Task %d error: %v\n", result.TaskID, result.Err)
} else {
fmt.Printf("Task %d result: %v\n", result.TaskID, result.Value)
}
}
}
8.3 动态协程池
go
type DynamicPool struct {
tasks chan func()
minWorkers int
maxWorkers int
workerCount int32
mu sync.Mutex
}
func NewDynamicPool(min, max int) *DynamicPool {
pool := &DynamicPool{
tasks: make(chan func(), 100),
minWorkers: min,
maxWorkers: max,
}
// 启动最小数量的worker
for i := 0; i < min; i++ {
pool.addWorker()
}
// 监控任务队列
go pool.monitor()
return pool
}
func (p *DynamicPool) addWorker() {
atomic.AddInt32(&p.workerCount, 1)
go func() {
defer atomic.AddInt32(&p.workerCount, -1)
for task := range p.tasks {
task()
}
}()
}
func (p *DynamicPool) monitor() {
ticker := time.NewTicker(time.Second)
defer ticker.Stop()
for range ticker.C {
taskCount := len(p.tasks)
workerCount := int(atomic.LoadInt32(&p.workerCount))
// 任务堆积,增加worker
if taskCount > workerCount && workerCount < p.maxWorkers {
p.addWorker()
fmt.Printf("Added worker, total: %d\n", workerCount+1)
}
// 任务少,减少worker(通过超时机制自然减少)
}
}
func (p *DynamicPool) Submit(task func()) {
p.tasks <- task
}
func (p *DynamicPool) Close() {
close(p.tasks)
}
8.4 高级协程池(ants库风格)
go
type Pool struct {
capacity int32
running int32
workers []*Worker
release chan struct{}
lock sync.Locker
cond *sync.Cond
once sync.Once
}
type Worker struct {
pool *Pool
task chan func()
recycled time.Time
}
func NewPool(size int) *Pool {
p := &Pool{
capacity: int32(size),
release: make(chan struct{}),
lock: new(sync.Mutex),
}
p.cond = sync.NewCond(p.lock)
return p
}
func (p *Pool) Submit(task func()) error {
if atomic.LoadInt32(&p.running) >= p.capacity {
return fmt.Errorf("pool is full")
}
w := p.getWorker()
w.task <- task
return nil
}
func (p *Pool) getWorker() *Worker {
p.lock.Lock()
defer p.lock.Unlock()
// 尝试复用worker
n := len(p.workers)
if n > 0 {
w := p.workers[n-1]
p.workers = p.workers[:n-1]
return w
}
// 创建新worker
atomic.AddInt32(&p.running, 1)
return p.createWorker()
}
func (p *Pool) createWorker() *Worker {
w := &Worker{
pool: p,
task: make(chan func(), 1),
}
go func() {
for {
select {
case t := <-w.task:
if t == nil {
atomic.AddInt32(&p.running, -1)
return
}
t()
p.revertWorker(w)
case <-p.release:
return
}
}
}()
return w
}
func (p *Pool) revertWorker(w *Worker) {
p.lock.Lock()
w.recycled = time.Now()
p.workers = append(p.workers, w)
p.cond.Signal()
p.lock.Unlock()
}
func (p *Pool) Release() {
p.once.Do(func() {
close(p.release)
p.lock.Lock()
for _, w := range p.workers {
w.task <- nil
}
p.workers = nil
p.lock.Unlock()
})
}
8.5 协程池最佳实践
go
// 1. 根据CPU核心数设置池大小
func optimalPoolSize() int {
// CPU密集型任务
cpuBound := runtime.NumCPU()
// I/O密集型任务
ioBound := runtime.NumCPU() * 2
return ioBound
}
// 2. 优雅关闭
type GracefulPool struct {
tasks chan func()
workers int
wg sync.WaitGroup
once sync.Once
}
func NewGracefulPool(workers int) *GracefulPool {
pool := &GracefulPool{
tasks: make(chan func()),
workers: workers,
}
for i := 0; i < workers; i++ {
pool.wg.Add(1)
go pool.worker()
}
return pool
}
func (p *GracefulPool) worker() {
defer p.wg.Done()
for task := range p.tasks {
task()
}
}
func (p *GracefulPool) Submit(task func()) {
p.tasks <- task
}
func (p *GracefulPool) Shutdown() {
p.once.Do(func() {
close(p.tasks)
p.wg.Wait()
})
}
// 3. 错误处理
type SafePool struct {
tasks chan func() error
errs chan error
}
func NewSafePool(workers int) *SafePool {
pool := &SafePool{
tasks: make(chan func() error),
errs: make(chan error, workers),
}
for i := 0; i < workers; i++ {
go func() {
for task := range pool.tasks {
if err := task(); err != nil {
pool.errs <- err
}
}
}()
}
return pool
}
9. 反射
9.1 反射基础
go
import "reflect"
// 反射允许程序检查和操作自身结构
func reflectionBasic() {
var x float64 = 3.4
// 获取类型
t := reflect.TypeOf(x)
fmt.Println("Type:", t) // float64
fmt.Println("Kind:", t.Kind()) // float64
// 获取值
v := reflect.ValueOf(x)
fmt.Println("Value:", v) // 3.4
fmt.Println("Type:", v.Type()) // float64
fmt.Println("Kind:", v.Kind()) // float64
fmt.Println("Float:", v.Float()) // 3.4
}
9.2 反射修改值
go
func reflectionModify() {
var x float64 = 3.4
v := reflect.ValueOf(&x) // 必须传指针
v = v.Elem() // 获取指针指向的值
if v.CanSet() {
v.SetFloat(7.1)
}
fmt.Println(x) // 7.1
}
// 修改结构体字段
type Person struct {
Name string
Age int
}
func modifyStruct() {
p := Person{Name: "Alice", Age: 30}
v := reflect.ValueOf(&p).Elem()
// 修改Name字段
nameField := v.FieldByName("Name")
if nameField.CanSet() {
nameField.SetString("Bob")
}
// 修改Age字段
ageField := v.FieldByName("Age")
if ageField.CanSet() {
ageField.SetInt(35)
}
fmt.Println(p) // {Bob 35}
}
9.3 反射检查结构体
go
type User struct {
ID int `json:"id" db:"user_id"`
Name string `json:"name" db:"user_name"`
age int // 私有字段
}
func inspectStruct() {
u := User{ID: 1, Name: "Alice", age: 30}
t := reflect.TypeOf(u)
v := reflect.ValueOf(u)
fmt.Println("Type:", t.Name())
fmt.Println("Number of fields:", t.NumField())
// 遍历字段
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
value := v.Field(i)
fmt.Printf("Field: %s, Type: %s, Value: %v\n",
field.Name,
field.Type,
value.Interface())
// 获取标签
if tag := field.Tag.Get("json"); tag != "" {
fmt.Printf(" JSON tag: %s\n", tag)
}
if tag := field.Tag.Get("db"); tag != "" {
fmt.Printf(" DB tag: %s\n", tag)
}
}
}
9.4 反射调用方法
go
type Calculator struct{}
func (c Calculator) Add(a, b int) int {
return a + b
}
func (c Calculator) Multiply(a, b int) int {
return a * b
}
func callMethod() {
calc := Calculator{}
v := reflect.ValueOf(calc)
// 调用Add方法
method := v.MethodByName("Add")
args := []reflect.Value{
reflect.ValueOf(10),
reflect.ValueOf(20),
}
results := method.Call(args)
fmt.Println("Result:", results[0].Int()) // 30
}
// 动态调用任意方法
func dynamicCall(obj interface{}, methodName string, args ...interface{}) ([]interface{}, error) {
v := reflect.ValueOf(obj)
method := v.MethodByName(methodName)
if !method.IsValid() {
return nil, fmt.Errorf("method %s not found", methodName)
}
// 转换参数
in := make([]reflect.Value, len(args))
for i, arg := range args {
in[i] = reflect.ValueOf(arg)
}
// 调用方法
results := method.Call(in)
// 转换返回值
out := make([]interface{}, len(results))
for i, result := range results {
out[i] = result.Interface()
}
return out, nil
}
func dynamicCallExample() {
calc := Calculator{}
result, err := dynamicCall(calc, "Add", 10, 20)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Println("Result:", result[0]) // 30
}
9.5 反射创建实例
go
// 通过类型创建实例
func createInstance() {
// 获取类型
var u User
t := reflect.TypeOf(u)
// 创建新实例
v := reflect.New(t) // 返回指针
elem := v.Elem()
// 设置字段
elem.Field(0).SetInt(123)
elem.Field(1).SetString("Dynamic User")
// 转换回原类型
newUser := v.Interface().(*User)
fmt.Println(*newUser) // {123 Dynamic User 0}
}
// 通过字符串创建类型
var typeRegistry = map[string]reflect.Type{
"User": reflect.TypeOf(User{}),
"Person": reflect.TypeOf(Person{}),
}
func createByName(typeName string) interface{} {
t, ok := typeRegistry[typeName]
if !ok {
return nil
}
v := reflect.New(t).Elem()
return v.Interface()
}
9.6 反射实战应用
go
// 1. JSON序列化/反序列化
func structToMap(obj interface{}) map[string]interface{} {
result := make(map[string]interface{})
v := reflect.ValueOf(obj)
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
t := v.Type()
for i := 0; i < v.NumField(); i++ {
field := t.Field(i)
value := v.Field(i)
// 只处理导出的字段
if field.PkgPath != "" {
continue
}
// 获取JSON标签
tag := field.Tag.Get("json")
if tag == "-" {
continue
}
name := field.Name
if tag != "" {
name = tag
}
result[name] = value.Interface()
}
return result
}
// 2. 深拷贝
func deepCopy(src interface{}) interface{} {
if src == nil {
return nil
}
original := reflect.ValueOf(src)
cpy := reflect.New(original.Type()).Elem()
copyRecursive(original, cpy)
return cpy.Interface()
}
func copyRecursive(src, dst reflect.Value) {
switch src.Kind() {
case reflect.Ptr:
if !src.IsNil() {
dst.Set(reflect.New(src.Elem().Type()))
copyRecursive(src.Elem(), dst.Elem())
}
case reflect.Struct:
for i := 0; i < src.NumField(); i++ {
if dst.Field(i).CanSet() {
copyRecursive(src.Field(i), dst.Field(i))
}
}
case reflect.Slice:
if !src.IsNil() {
dst.Set(reflect.MakeSlice(src.Type(), src.Len(), src.Cap()))
for i := 0; i < src.Len(); i++ {
copyRecursive(src.Index(i), dst.Index(i))
}
}
case reflect.Map:
if !src.IsNil() {
dst.Set(reflect.MakeMap(src.Type()))
for _, key := range src.MapKeys() {
originalValue := src.MapIndex(key)
copyValue := reflect.New(originalValue.Type()).Elem()
copyRecursive(originalValue, copyValue)
dst.SetMapIndex(key, copyValue)
}
}
default:
dst.Set(src)
}
}
// 3. 验证器
type Validator struct {
validators map[string]func(interface{}) error
}
func NewValidator() *Validator {
return &Validator{
validators: map[string]func(interface{}) error{
"required": func(v interface{}) error {
if reflect.ValueOf(v).IsZero() {
return fmt.Errorf("field is required")
}
return nil
},
"min": func(v interface{}) error {
// 实现最小值检查
return nil
},
},
}
}
func (v *Validator) Validate(obj interface{}) error {
val := reflect.ValueOf(obj)
if val.Kind() == reflect.Ptr {
val = val.Elem()
}
typ := val.Type()
for i := 0; i < val.NumField(); i++ {
field := typ.Field(i)
value := val.Field(i)
// 解析validate标签
tag := field.Tag.Get("validate")
if tag == "" {
continue
}
// 执行验证
if validator, ok := v.validators[tag]; ok {
if err := validator(value.Interface()); err != nil {
return fmt.Errorf("field %s: %w", field.Name, err)
}
}
}
return nil
}
// 4. ORM映射
func scanRow(rows *sql.Rows, dest interface{}) error {
destv := reflect.ValueOf(dest)
if destv.Kind() != reflect.Ptr {
return fmt.Errorf("dest must be a pointer")
}
elem := destv.Elem()
if elem.Kind() != reflect.Struct {
return fmt.Errorf("dest must be a struct pointer")
}
columns, err := rows.Columns()
if err != nil {
return err
}
values := make([]interface{}, len(columns))
for i := range values {
values[i] = new(interface{})
}
if err := rows.Scan(values...); err != nil {
return err
}
for i, col := range columns {
field := elem.FieldByName(col)
if field.IsValid() && field.CanSet() {
val := reflect.ValueOf(values[i]).Elem().Interface()
field.Set(reflect.ValueOf(val))
}
}
return nil
}
9.7 反射的性能和注意事项
go
// ⚠️ 反射的性能开销
// 基准测试对比
func BenchmarkDirect(b *testing.B) {
u := User{ID: 1, Name: "Alice"}
for i := 0; i < b.N; i++ {
_ = u.ID
_ = u.Name
}
}
func BenchmarkReflection(b *testing.B) {
u := User{ID: 1, Name: "Alice"}
v := reflect.ValueOf(u)
for i := 0; i < b.N; i++ {
_ = v.Field(0).Int()
_ = v.Field(1).String()
}
}
// 反射慢10-100倍
// ✅ 反射的最佳实践
// 1. 只在必要时使用反射
// 2. 缓存反射结果
var typeCache sync.Map
func getType(obj interface{}) reflect.Type {
key := reflect.TypeOf(obj)
if t, ok := typeCache.Load(key); ok {
return t.(reflect.Type)
}
t := reflect.TypeOf(obj)
typeCache.Store(key, t)
return t
}
// 3. 避免在循环中使用反射
// ❌ 不好
for i := 0; i < 1000; i++ {
t := reflect.TypeOf(obj) // 重复反射
}
// ✅ 好
t := reflect.TypeOf(obj)
for i := 0; i < 1000; i++ {
// 使用缓存的类型
}
// 4. 类型断言优于反射
// ❌ 不好
v := reflect.ValueOf(obj)
if v.Kind() == reflect.Int {
val := v.Int()
}
// ✅ 好
if val, ok := obj.(int); ok {
// 使用val
}
10. 泛型
10.1 泛型基础(Go 1.18+)
go
// 泛型函数
func Print[T any](value T) {
fmt.Println(value)
}
func printExample() {
Print[int](42)
Print[string]("hello")
Print(3.14) // 类型推断
}
// 多类型参数
func Pair[T, U any](first T, second U) (T, U) {
return first, second
}
func pairExample() {
a, b := Pair(1, "hello")
fmt.Println(a, b) // 1 hello
}
10.2 类型约束
go
// 使用comparable约束(可比较类型)
func Equal[T comparable](a, b T) bool {
return a == b
}
func equalExample() {
fmt.Println(Equal(1, 1)) // true
fmt.Println(Equal("a", "b")) // false
// fmt.Println(Equal([]int{}, []int{})) // 编译错误:slice不可比较
}
// 自定义约束
type Number interface {
int | int64 | float64
}
func Add[T Number](a, b T) T {
return a + b
}
func addExample() {
fmt.Println(Add(1, 2)) // 3
fmt.Println(Add(1.5, 2.3)) // 3.8
// fmt.Println(Add("a", "b")) // 编译错误
}
// 近似约束(允许自定义类型)
type Numeric interface {
~int | ~int64 | ~float64
}
type MyInt int
func Sum[T Numeric](nums []T) T {
var total T
for _, num := range nums {
total += num
}
return total
}
func sumExample() {
ints := []int{1, 2, 3}
fmt.Println(Sum(ints)) // 6
myInts := []MyInt{1, 2, 3}
fmt.Println(Sum(myInts)) // 6
}
10.3 泛型类型
go
// 泛型结构体
type Stack[T any] struct {
items []T
}
func NewStack[T any]() *Stack[T] {
return &Stack[T]{
items: make([]T, 0),
}
}
func (s *Stack[T]) Push(item T) {
s.items = append(s.items, item)
}
func (s *Stack[T]) Pop() (T, bool) {
if len(s.items) == 0 {
var zero T
return zero, false
}
item := s.items[len(s.items)-1]
s.items = s.items[:len(s.items)-1]
return item, true
}
func (s *Stack[T]) IsEmpty() bool {
return len(s.items) == 0
}
func stackExample() {
// 整数栈
intStack := NewStack[int]()
intStack.Push(1)
intStack.Push(2)
val, ok := intStack.Pop()
fmt.Println(val, ok) // 2 true
// 字符串栈
strStack := NewStack[string]()
strStack.Push("hello")
strStack.Push("world")
}
// 泛型Map
type SafeMap[K comparable, V any] struct {
mu sync.RWMutex
data map[K]V
}
func NewSafeMap[K comparable, V any]() *SafeMap[K, V] {
return &SafeMap[K, V]{
data: make(map[K]V),
}
}
func (m *SafeMap[K, V]) Set(key K, value V) {
m.mu.Lock()
defer m.mu.Unlock()
m.data[key] = value
}
func (m *SafeMap[K, V]) Get(key K) (V, bool) {
m.mu.RLock()
defer m.mu.RUnlock()
val, ok := m.data[key]
return val, ok
}
func (m *SafeMap[K, V]) Delete(key K) {
m.mu.Lock()
defer m.mu.Unlock()
delete(m.data, key)
}
10.4 泛型函数实战
go
// 1. 泛型切片操作
func Map[T, U any](slice []T, fn func(T) U) []U {
result := make([]U, len(slice))
for i, v := range slice {
result[i] = fn(v)
}
return result
}
func Filter[T any](slice []T, fn func(T) bool) []T {
result := make([]T, 0)
for _, v := range slice {
if fn(v) {
result = append(result, v)
}
}
return result
}
func Reduce[T, U any](slice []T, initial U, fn func(U, T) U) U {
result := initial
for _, v := range slice {
result = fn(result, v)
}
return result
}
func sliceOpsExample() {
nums := []int{1, 2, 3, 4, 5}
// Map: 每个元素乘2
doubled := Map(nums, func(n int) int {
return n * 2
})
fmt.Println(doubled) // [2 4 6 8 10]
// Filter: 筛选偶数
evens := Filter(nums, func(n int) bool {
return n%2 == 0
})
fmt.Println(evens) // [2 4]
// Reduce: 求和
sum := Reduce(nums, 0, func(acc, n int) int {
return acc + n
})
fmt.Println(sum) // 15
}
// 2. 泛型排序
func Sort[T any](slice []T, less func(a, b T) bool) {
n := len(slice)
for i := 0; i < n-1; i++ {
for j := 0; j < n-i-1; j++ {
if less(slice[j+1], slice[j]) {
slice[j], slice[j+1] = slice[j+1], slice[j]
}
}
}
}
func sortExample() {
nums := []int{5, 2, 8, 1, 9}
Sort(nums, func(a, b int) bool {
return a < b
})
fmt.Println(nums) // [1 2 5 8 9]
type Person struct {
Name string
Age int
}
people := []Person{
{"Alice", 30},
{"Bob", 25},
{"Charlie", 35},
}
Sort(people, func(a, b Person) bool {
return a.Age < b.Age
})
fmt.Println(people)
}
// 3. 泛型链表
type Node[T any] struct {
Value T
Next *Node[T]
}
type LinkedList[T any] struct {
Head *Node[T]
}
func (l *LinkedList[T]) Add(value T) {
node := &Node[T]{Value: value}
if l.Head == nil {
l.Head = node
return
}
current := l.Head
for current.Next != nil {
current = current.Next
}
current.Next = node
}
func (l *LinkedList[T]) ForEach(fn func(T)) {
current := l.Head
for current != nil {
fn(current.Value)
current = current.Next
}
}
// 4. 泛型Option类型
type Option[T any] struct {
value *T
}
func Some[T any](value T) Option[T] {
return Option[T]{value: &value}
}
func None[T any]() Option[T] {
return Option[T]{value: nil}
}
func (o Option[T]) IsSome() bool {
return o.value != nil
}
func (o Option[T]) IsNone() bool {
return o.value == nil
}
func (o Option[T]) Unwrap() T {
if o.value == nil {
panic("unwrap on None")
}
return *o.value
}
func (o Option[T]) UnwrapOr(defaultValue T) T {
if o.value == nil {
return defaultValue
}
return *o.value
}
func optionExample() {
some := Some(42)
fmt.Println(some.Unwrap()) // 42
none := None[int]()
fmt.Println(none.UnwrapOr(0)) // 0
}
// 5. 泛型Result类型
type Result[T any] struct {
value *T
err error
}
func Ok[T any](value T) Result[T] {
return Result[T]{value: &value}
}
func Err[T any](err error) Result[T] {
return Result[T]{err: err}
}
func (r Result[T]) IsOk() bool {
return r.err == nil
}
func (r Result[T]) IsErr() bool {
return r.err != nil
}
func (r Result[T]) Unwrap() (T, error) {
if r.err != nil {
var zero T
return zero, r.err
}
return *r.value, nil
}
10.5 泛型接口
go
// 泛型接口
type Container[T any] interface {
Add(item T)
Get(index int) (T, bool)
Size() int
}
// 实现泛型接口
type ArrayList[T any] struct {
items []T
}
func (a *ArrayList[T]) Add(item T) {
a.items = append(a.items, item)
}
func (a *ArrayList[T]) Get(index int) (T, bool) {
if index < 0 || index >= len(a.items) {
var zero T
return zero, false
}
return a.items[index], true
}
func (a *ArrayList[T]) Size() int {
return len(a.items)
}
// 使用泛型接口
func ProcessContainer[T any](c Container[T], items []T) {
for _, item := range items {
c.Add(item)
}
fmt.Println("Container size:", c.Size())
}
10.6 泛型的限制和最佳实践
go
// ⚠️ 泛型的限制
// 1. 不能用于方法的类型参数
type MyStruct struct{}
// ❌ 不支持
// func (m MyStruct) Method[T any](value T) {}
// ✅ 可以用于类型的方法
type MyGenericStruct[T any] struct {
value T
}
func (m MyGenericStruct[T]) GetValue() T {
return m.value
}
// 2. 类型参数不能用于类型断言或类型switch
func process[T any](value T) {
// ❌ 不支持
// switch value.(type) { ... }
// ✅ 使用反射
v := reflect.ValueOf(value)
switch v.Kind() {
case reflect.Int:
// ...
}
}
// ✅ 泛型最佳实践
// 1. 优先使用接口而非泛型
// 如果现有接口满足需求,使用接口
func ProcessReader(r io.Reader) {} // ✅ 好
// 只有需要保留类型信息时才用泛型
func Transform[T any](items []T, fn func(T) T) []T { // ✅ 好
// 保留了T的类型信息
}
// 2. 约束应该尽可能宽松
// ❌ 过于严格
type IntOnly interface {
int
}
// ✅ 更灵活
type Number interface {
~int | ~int64 | ~float64
}
// 3. 避免过度泛型化
// ❌ 不必要的泛型
func Add[T int](a, b T) T {
return a + b
}
// ✅ 简单函数不需要泛型
func Add(a, b int) int {
return a + b
}
// 4. 泛型命名规范
// 单个类型参数:T, U, V
// 特定含义:K(Key), V(Value), E(Element)
type Map[K comparable, V any] struct {
data map[K]V
}
总结
本指南全面覆盖了Go语言并发编程的核心知识:
📚 核心概念
- 并发模型:理解并发vs并行,掌握CSP模型
- Goroutine:轻量级线程的创建、调度和管理
- Channel:Go并发的核心通信机制
- 同步原语:Mutex、RWMutex、WaitGroup、Once等
- Select:优雅的多路复用
- Context:请求范围的控制和取消
- 定时器:Timer和Ticker的实战应用
- 协程池:高效的goroutine管理
- 反射:运行时类型操作
- 泛型:类型安全的代码复用
🎯 关键要点
- 通信优于共享:用channel传递数据
- 避免泄漏:确保goroutine能够退出
- 正确同步:选择合适的同步原语
- 优雅关闭:使用Context控制生命周期
- 性能优化:协程池、对象池、原子操作
- 类型安全:善用泛型提高代码质量
💡 最佳实践
- 始终考虑goroutine的退出机制
- 使用Context传递取消信号
- Channel的发送者负责关闭
- 避免在循环中启动无限goroutine
- 使用select处理超时和取消
- 反射谨慎使用,注意性能
- 泛型用于需要类型安全的场景