
Go语言并发编程Goroutine与Channel深度解析一、并发编程基础在Go语言中并发是其核心特性之一。Go通过Goroutine和Channel提供了简洁而强大的并发模型让开发者能够轻松编写高效的并发程序。并发与并行的区别概念定义特点并发多个任务交替执行单核CPU即可实现并行多个任务同时执行需要多核CPU支持Goroutine简介Goroutine是Go语言中的轻量级线程由Go运行时管理。相比操作系统线程Goroutine具有以下优势启动开销小约2KB栈空间上下文切换更快支持大量并发轻松创建数万个Goroutine二、Goroutine基础创建Goroutinepackage main import ( fmt time ) func sayHello(name string) { for i : 0; i 5; i { fmt.Printf(Hello, %s! Count: %d\n, name, i) time.Sleep(100 * time.Millisecond) } } func main() { // 启动Goroutine go sayHello(Gopher) // 主Goroutine继续执行 for i : 0; i 3; i { fmt.Printf(Main routine: %d\n, i) time.Sleep(150 * time.Millisecond) } // 等待Goroutine完成 time.Sleep(1 * time.Second) }匿名函数Goroutinefunc main() { go func(msg string) { fmt.Println(msg) }(Hello from goroutine) time.Sleep(100 * time.Millisecond) }三、Channel通信机制Channel基础Channel是Goroutine之间的通信管道用于在不同Goroutine之间传递数据。// 创建无缓冲Channel ch : make(chan int) // 创建带缓冲的Channel ch : make(chan int, 10)Channel操作package main import fmt func producer(ch chan- int) { for i : 0; i 5; i { ch - i // 发送数据到Channel fmt.Printf(Produced: %d\n, i) } close(ch) // 关闭Channel } func consumer(ch -chan int) { for num : range ch { // 从Channel接收数据 fmt.Printf(Consumed: %d\n, num) } } func main() { ch : make(chan int, 2) go producer(ch) go consumer(ch) // 等待完成 fmt.Scanln() }双向与单向Channelfunc sendData(ch chan- int) { ch - 42 } func receiveData(ch -chan int) { data : -ch fmt.Println(data) } func main() { ch : make(chan int) go sendData(ch) go receiveData(ch) fmt.Scanln() }四、并发模式Worker Pool模式package main import ( fmt time ) func worker(id int, jobs -chan int, results chan- int) { for job : range jobs { fmt.Printf(Worker %d processing job %d\n, id, job) time.Sleep(time.Second) results - job * 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) } // 发送9个任务 for j : 1; j 9; j { jobs - j } close(jobs) // 收集结果 for r : 1; r 9; r { -results } }Fan-Out/Fan-In模式package main import ( fmt sync ) func generator(nums ...int) -chan int { out : make(chan int) go func() { for _, n : range nums { out - n } close(out) }() return out } func square(in -chan int) -chan int { out : make(chan int) go func() { for n : range in { out - n * n } close(out) }() return out } func merge(cs ...-chan int) -chan int { var wg sync.WaitGroup out : make(chan int) output : func(c -chan int) { for n : range c { out - n } wg.Done() } wg.Add(len(cs)) for _, c : range cs { go output(c) } go func() { wg.Wait() close(out) }() return out } func main() { in : generator(1, 2, 3, 4, 5) // Fan-Out: 多个square同时处理 c1 : square(in) c2 : square(in) c3 : square(in) // Fan-In: 合并结果 for n : range merge(c1, c2, c3) { fmt.Println(n) } }五、同步原语WaitGrouppackage main import ( fmt sync time ) func task(id int, wg *sync.WaitGroup) { defer wg.Done() fmt.Printf(Task %d starting\n, id) time.Sleep(time.Second) fmt.Printf(Task %d completed\n, id) } func main() { var wg sync.WaitGroup for i : 1; i 5; i { wg.Add(1) go task(i, wg) } wg.Wait() fmt.Println(All tasks completed) }Mutexpackage main import ( fmt sync ) type Counter struct { mu sync.Mutex value int } func (c *Counter) Increment() { c.mu.Lock() defer c.mu.Unlock() c.value } func (c *Counter) Value() int { c.mu.Lock() defer c.mu.Unlock() return c.value } func main() { counter : Counter{} var wg sync.WaitGroup for i : 0; i 1000; i { wg.Add(1) go func() { defer wg.Done() counter.Increment() }() } wg.Wait() fmt.Printf(Final count: %d\n, counter.Value()) }RWMutexpackage main import ( fmt sync time ) type DataStore struct { mu sync.RWMutex data map[string]string } func (ds *DataStore) Get(key string) string { ds.mu.RLock() defer ds.mu.RUnlock() return ds.data[key] } func (ds *DataStore) Set(key, value string) { ds.mu.Lock() defer ds.mu.Unlock() ds.data[key] value } func main() { ds : DataStore{data: make(map[string]string)} ds.Set(key1, value1) var wg sync.WaitGroup // 多个读操作可以并发执行 for i : 0; i 10; i { wg.Add(1) go func() { defer wg.Done() fmt.Println(ds.Get(key1)) time.Sleep(10 * time.Millisecond) }() } wg.Wait() }六、Context包Context基础package main import ( context fmt time ) func doWork(ctx context.Context) { for { select { case -ctx.Done(): fmt.Println(Work cancelled) return default: fmt.Println(Working...) time.Sleep(200 * time.Millisecond) } } } func main() { ctx, cancel : context.WithTimeout(context.Background(), 1*time.Second) defer cancel() go doWork(ctx) time.Sleep(2 * time.Second) }Context传递package main import ( context fmt time ) func trace(ctx context.Context, msg string) { if span, ok : ctx.Value(span).(string); ok { fmt.Printf([%s] %s\n, span, msg) } else { fmt.Printf([unknown] %s\n, msg) } } func handler(ctx context.Context) { ctx context.WithValue(ctx, span, handler) trace(ctx, starting) go worker(ctx) time.Sleep(500 * time.Millisecond) trace(ctx, finished) } func worker(ctx context.Context) { ctx context.WithValue(ctx, span, worker) trace(ctx, processing) time.Sleep(300 * time.Millisecond) trace(ctx, completed) } func main() { ctx : context.Background() handler(ctx) }七、并发安全实践避免共享状态// 不好的做法共享状态 var count int var mu sync.Mutex func increment() { mu.Lock() count mu.Unlock() } // 好的做法使用Channel传递状态 func counter(ch chan int) { count : 0 for { count ch - count } }避免死锁// 死锁示例 func deadlock() { ch1 : make(chan int) ch2 : make(chan int) go func() { ch1 - -ch2 // 等待ch2的数据但ch2没有发送 }() go func() { ch2 - -ch1 // 等待ch1的数据但ch1没有发送 }() // 死锁 }检测数据竞争go run -race main.go八、性能优化Goroutine数量控制package main import ( fmt time ) func main() { maxWorkers : 10 sem : make(chan struct{}, maxWorkers) for i : 0; i 100; i { sem - struct{}{} // 获取信号量 go func(id int) { defer func() { -sem }() // 释放信号量 fmt.Printf(Worker %d started\n, id) time.Sleep(100 * time.Millisecond) fmt.Printf(Worker %d finished\n, id) }(i) } // 等待所有worker完成 for i : 0; i maxWorkers; i { sem - struct{}{} } }Channel缓冲优化// 无缓冲Channel - 同步通信 ch : make(chan int) // 带缓冲Channel - 异步通信提高吞吐量 ch : make(chan int, 100)九、总结Go语言的并发模型基于Goroutine和Channel提供了简洁而强大的并发编程能力。通过掌握以下要点可以编写出高效、安全的并发程序Goroutine轻量级执行单元由Go运行时管理ChannelGoroutine间的通信管道遵循CSP模型同步原语WaitGroup、Mutex、RWMutex等用于协调并发Context用于传递请求范围的值和取消信号并发模式Worker Pool、Fan-Out/Fan-In等经典模式Go语言的并发设计理念是不要通过共享内存来通信而要通过通信来共享内存这使得并发编程更加安全和易于理解。