并发模式
并发模式简介
并发模式提供了结构化的方法来解决Go语言中复杂的并发编程挑战。
常见并发模式
模式 |
描述 |
使用场景 |
工作池(Worker Pool) |
限制并发工作线程数量 |
资源密集型任务 |
扇出/扇入(Fan-Out/Fan-In) |
分配和收集工作 |
并行处理 |
管道(Pipeline) |
数据处理阶段 |
流处理 |
选择模式(Select Pattern) |
通道多路复用 |
并发通信 |
工作池模式
package main
import (
"fmt"
"sync"
)
func worker(id int, jobs <-chan int, results chan<- int, wg *sync.WaitGroup) {
defer wg.Done()
for job := range jobs {
fmt.Printf("Worker %d processing job %d\n", id, job)
results <- job * 2
}
}
func main() {
jobs := make(chan int, 100)
results := make(chan int, 100)
var wg sync.WaitGroup
// 创建工作池
for w := 1; w <= 3; w++ {
wg.Add(1)
go worker(w, jobs, results, &wg)
}
// 发送任务
for j := 1; j <= 5; j++ {
jobs <- j
}
close(jobs)
wg.Wait()
close(results)
// 收集结果
for result := range results {
fmt.Println("Result:", result)
}
}
工作池可视化
graph TD
A[任务队列] --> B[工作线程1]
A --> C[工作线程2]
A --> D[工作线程3]
B --> E[结果]
C --> E
D --> E
扇出/扇入模式
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)
c1 := square(in)
c2 := square(in)
for n := range merge(c1, c2) {
fmt.Println(n)
}
}
并发通信的选择模式
package main
import (
"fmt"
"time"
)
func main() {
ch1 := make(chan string)
ch2 := make(chan string)
go func() {
time.Sleep(time.Second)
ch1 <- "first"
}()
go func() {
time.Sleep(2 * time.Second)
ch2 <- "second"
}()
select {
case msg1 := <-ch1:
fmt.Println("Received:", msg1)
case msg2 := <-ch2:
fmt.Println("Received:", msg2)
case <-time.After(3 * time.Second):
fmt.Println("Timeout")
}
}
并发模式流程
graph TD
A[输入数据] --> B{并发处理}
B --> C[工作线程1]
B --> D[工作线程2]
B --> E[工作线程3]
C --> F[结果聚合]
D --> F
E --> F
最佳实践
- 使用通道进行通信
- 避免共享状态
- 设计支持取消操作
- 优雅地处理错误
LabEx学习提示
在LabEx,我们建议通过实际编码挑战来实践这些模式,以培养高级并发编程技能。
要点总结
- 并发模式解决复杂的同步问题
- 为特定用例选择合适的模式
- 理解通道通信
- 尽量减少并发代码的复杂性