40分钟学 Go 语言高并发:Select多路复用

Select多路复用

学习目标

知识点 掌握程度 应用场景
select实现原理 深入理解底层机制 channel通信和多路选择
超时处理 掌握超时控制方法 避免阻塞和资源浪费
优先级控制 理解优先级实现 处理多个channel的顺序
性能考虑 了解性能优化点 高并发场景优化

1. Select实现原理

让我们通过一个完整的例子来理解select的工作原理:

go 复制代码
package main

import (
    "fmt"
    "math/rand"
    "sync"
    "time"
)

// 数据生产者
type Producer struct {
    dataChan chan int
    done     chan struct{}
}

// 创建新的生产者
func NewProducer() *Producer {
    return &Producer{
        dataChan: make(chan int, 100),
        done:     make(chan struct{}),
    }
}

// 启动生产
func (p *Producer) Start() {
    go func() {
        defer close(p.dataChan)
        for {
            select {
            case <-p.done:
                fmt.Println("Producer: received stop signal")
                return
            default:
                // 生成随机数据
                data := rand.Intn(100)
                select {
                case p.dataChan <- data:
                    fmt.Printf("Producer: sent data %d\n", data)
                    time.Sleep(time.Millisecond * 100)
                case <-p.done:
                    fmt.Println("Producer: received stop signal while sending")
                    return
                }
            }
        }
    }()
}

// 停止生产
func (p *Producer) Stop() {
    close(p.done)
}

// 获取数据通道
func (p *Producer) DataChan() <-chan int {
    return p.dataChan
}

// 数据处理器
type Processor struct {
    producers []*Producer
    results   chan int
    done      chan struct{}
}

// 创建新的处理器
func NewProcessor(producerCount int) *Processor {
    producers := make([]*Producer, producerCount)
    for i := 0; i < producerCount; i++ {
        producers[i] = NewProducer()
    }
    
    return &Processor{
        producers: producers,
        results:   make(chan int, producerCount*100),
        done:      make(chan struct{}),
    }
}

// 启动处理
func (p *Processor) Start() {
    // 启动所有生产者
    for i, producer := range p.producers {
        producer.Start()
        
        // 为每个生产者启动一个处理goroutine
        go func(id int, prod *Producer) {
            for {
                select {
                case data, ok := <-prod.DataChan():
                    if !ok {
                        fmt.Printf("Processor %d: producer channel closed\n", id)
                        return
                    }
                    
                    // 处理数据
                    result := data * 2
                    
                    select {
                    case p.results <- result:
                        fmt.Printf("Processor %d: processed data %d -> %d\n", 
                            id, data, result)
                    case <-p.done:
                        return
                    }
                    
                case <-p.done:
                    fmt.Printf("Processor %d: received stop signal\n", id)
                    return
                }
            }
        }(i, producer)
    }
}

// 停止处理
func (p *Processor) Stop() {
    close(p.done)
    for _, producer := range p.producers {
        producer.Stop()
    }
}

// 获取结果通道
func (p *Processor) Results() <-chan int {
    return p.results
}

func main() {
    // 创建有3个生产者的处理器
    processor := NewProcessor(3)
    
    // 启动处理器
    processor.Start()
    
    // 创建结果收集器
    var wg sync.WaitGroup
    wg.Add(1)
    
    go func() {
        defer wg.Done()
        count := 0
        for result := range processor.Results() {
            fmt.Printf("Collector: received result %d\n", result)
            count++
            if count >= 20 { // 收集20个结果后停止
                processor.Stop()
                break
            }
        }
    }()
    
    // 等待处理完成
    wg.Wait()
    fmt.Println("Main: processing completed")
}

1.1 Select执行流程图

2. 超时处理

让我们实现一个带有超时控制的服务请求处理系统:

go 复制代码
package main

import (
    "context"
    "fmt"
    "math/rand"
    "sync"
    "time"
)

// 请求处理器
type RequestHandler struct {
    requests  chan Request
    responses chan Response
    done      chan struct{}
    wg        sync.WaitGroup
}

// 请求结构
type Request struct {
    ID      int
    Timeout time.Duration
    Data    string
}

// 响应结构
type Response struct {
    RequestID int
    Result    string
    Error     error
}

// 创建新的请求处理器
func NewRequestHandler() *RequestHandler {
    return &RequestHandler{
        requests:  make(chan Request, 100),
        responses: make(chan Response, 100),
        done:      make(chan struct{}),
    }
}

// 启动处理器
func (h *RequestHandler) Start(workers int) {
    for i := 0; i < workers; i++ {
        h.wg.Add(1)
        go h.worker(i)
    }
}

// 工作协程
func (h *RequestHandler) worker(id int) {
    defer h.wg.Done()
    
    for {
        select {
        case req, ok := <-h.requests:
            if !ok {
                fmt.Printf("Worker %d: request channel closed\n", id)
                return
            }
            
            // 创建context用于超时控制
            ctx, cancel := context.WithTimeout(context.Background(), req.Timeout)
            
            // 处理请求
            response := h.processRequest(ctx, req)
            
            // 发送响应
            select {
            case h.responses <- response:
                fmt.Printf("Worker %d: sent response for request %d\n", 
                    id, req.ID)
            case <-h.done:
                cancel()
                return
            }
            
            cancel() // 清理context
            
        case <-h.done:
            fmt.Printf("Worker %d: received stop signal\n", id)
            return
        }
    }
}

// 处理单个请求
func (h *RequestHandler) processRequest(ctx context.Context, req Request) Response {
    // 模拟处理时间
    processTime := time.Duration(rand.Intn(int(req.Timeout))) + req.Timeout/2
    
    select {
    case <-time.After(processTime):
        return Response{
            RequestID: req.ID,
            Result:   fmt.Sprintf("Processed: %s", req.Data),
        }
    case <-ctx.Done():
        return Response{
            RequestID: req.ID,
            Error:    ctx.Err(),
        }
    }
}

// 提交请求
func (h *RequestHandler) SubmitRequest(req Request) error {
    select {
    case h.requests <- req:
        return nil
    case <-h.done:
        return fmt.Errorf("handler is stopped")
    }
}

// 获取响应
func (h *RequestHandler) GetResponse() (Response, error) {
    select {
    case resp := <-h.responses:
        return resp, nil
    case <-h.done:
        return Response{}, fmt.Errorf("handler is stopped")
    }
}

// 停止处理器
func (h *RequestHandler) Stop() {
    close(h.done)
    h.wg.Wait()
    close(h.requests)
    close(h.responses)
}

func main() {
    // 创建请求处理器
    handler := NewRequestHandler()
    handler.Start(3)
    
    // 发送一些测试请求
    requests := []Request{
        {ID: 1, Timeout: time.Second, Data: "Fast request"},
        {ID: 2, Timeout: time.Second * 2, Data: "Normal request"},
        {ID: 3, Timeout: time.Millisecond * 500, Data: "Quick request"},
        {ID: 4, Timeout: time.Second * 3, Data: "Slow request"},
    }
    
    // 提交请求
    for _, req := range requests {
        if err := handler.SubmitRequest(req); err != nil {
            fmt.Printf("Failed to submit request %d: %v\n", req.ID, err)
            continue
        }
        fmt.Printf("Submitted request %d\n", req.ID)
    }
    
    // 收集响应
    var wg sync.WaitGroup
    wg.Add(1)
    
    go func() {
        defer wg.Done()
        for i := 0; i < len(requests); i++ {
            resp, err := handler.GetResponse()
            if err != nil {
                fmt.Printf("Failed to get response: %v\n", err)
                continue
            }
            
            if resp.Error != nil {
                fmt.Printf("Request %d failed: %v\n", resp.RequestID, resp.Error)
            } else {
                fmt.Printf("Request %d succeeded: %s\n", resp.RequestID, resp.Result)
            }
        }
    }()
    
    // 等待所有响应处理完成
    wg.Wait()
    
    // 停止处理器
    handler.Stop()
    fmt.Println("Main: processing completed")
}

3. 优先级控制

让我们实现一个带有优先级控制的任务调度系统:

go 复制代码
package main

import (
    "fmt"
    "math/rand"
    "sort"
    "sync"
    "time"
)

// 优先级级别
const (
    PriorityHigh = iota
    PriorityMedium
    PriorityLow
)

// 任务结构
type Task struct {
    ID       int
    Priority int
    Action   func() error
}

// 优先级调度器
type PriorityScheduler struct {
    highPriority   chan Task
    mediumPriority chan Task
    lowPriority    chan Task
    results        chan error
    done           chan struct{}
    wg             sync.WaitGroup
}

// 创建新的调度器
func NewPriorityScheduler() *PriorityScheduler {
    return &PriorityScheduler{
        highPriority:   make(chan Task, 100),
        mediumPriority: make(chan Task, 100),
        lowPriority:    make(chan Task, 100),
        results:        make(chan error, 100),
        done:          make(chan struct{}),
    }
}

// 启动调度器
func (s *PriorityScheduler) Start(workers int) {
    for i := 0; i < workers; i++ {
        s.wg.Add(1)
        go s.worker(i)
    }
}

// 工作协程
func (s *PriorityScheduler) worker(id int) {
    defer s.wg.Done()

    for {
        // 使用优先级顺序处理任务
        select {
        case <-s.done:
            return
            
        // 高优先级任务
        case task := <-s.highPriority:
            fmt.Printf("Worker %d: processing high priority task %d\n", 
                id, task.ID)
            s.results <- task.Action()
            
        // 如果没有高优先级任务,检查中优先级
        default:
            select {
            case <-s.done:
                return
                
            case task := <-s.highPriority:
                fmt.Printf("Worker %d: processing high priority task %d\n", 
                    id, task.ID)
                s.results <- task.Action()
                
            case task := <-s.mediumPriority:
                fmt.Printf("Worker %d: processing medium priority task %d\n", 
                    id, task.ID)
                s.results <- task.Action()
                
            // 如果没有中优先级任务,检查低优先级
            default:
                select {
                case <-s.done:
                    return
                    
                case task := <-s.highPriority:
                    fmt.Printf("Worker %d: processing high priority task %d\n", 
                        id, task.ID)
                    s.results <- task.Action()
                    
                case task := <-s.mediumPriority:
                    fmt.Printf("Worker %d: processing medium priority task %d\n", 
                        id, task.ID)
                    s.results <- task.Action()
                    
                case task := <-s.lowPriority:
                    fmt.Printf("Worker %d: processing low priority task %d\n", 
                        id, task.ID)
                    s.results <- task.Action()
                }
            }
        }
    }
}

// 提交任务
func (s *PriorityScheduler) SubmitTask(task Task) error {
    var targetChan chan Task
    
    switch task.Priority {
    case PriorityHigh:
        targetChan = s.highPriority
    case PriorityMedium:
        targetChan = s.mediumPriority
    case PriorityLow:
        targetChan = s.lowPriority
    default:
        return fmt.Errorf("invalid priority level: %d", task.Priority)
    }
    
    select {
    case targetChan <- task:
        return nil
    case <-s.done:
        return fmt.Errorf("scheduler is stopped")
    }
}

// 获取结果
func (s *PriorityScheduler) Results() <-chan error {
    return s.results
}

// 停止调度器
func (s *PriorityScheduler) Stop() {
    close(s.done)
    s.wg.Wait()
    close(s.highPriority)
    close(s.mediumPriority)
    close(s.lowPriority)
    close(s.results)
}

// 创建模拟任务
func createTask(id int, priority int, duration time.Duration) Task {
    return Task{
        ID:       id,
        Priority: priority,
        Action: func() error {
            time.Sleep(duration)
            if rand.Float32() < 0.1 { // 10%的失败率
                return fmt.Errorf("task %d failed", id)
            }
            return nil
        },
    }
}

func main() {
    // 创建调度器
    scheduler := NewPriorityScheduler()
    scheduler.Start(3)
    
    // 创建一些测试任务
    var tasks []Task
    for i := 0; i < 15; i++ {
        priority := i % 3 // 在三个优先级之间循环
        duration := time.Millisecond * time.Duration(rand.Intn(500)+100)
        tasks = append(tasks, createTask(i, priority, duration))
    }
    
    // 随机打乱任务顺序
    rand.Shuffle(len(tasks), func(i, j int) {
        tasks[i], tasks[j] = tasks[j], tasks[i]
    })
    
    // 提交任务
    for _, task := range tasks {
        if err := scheduler.SubmitTask(task); err != nil {
            fmt.Printf("Failed to submit task %d: %v\n", task.ID, err)
            continue
        }
        fmt.Printf("Submitted task %d with priority %d\n", task.ID, task.Priority)
    }
    
    // 收集结果
    var wg sync.WaitGroup
    wg.Add(1)
    
    go func() {
        defer wg.Done()
        completed := 0
        failures := 0
        
        for err := range scheduler.Results() {
            if err != nil {
                failures++
                fmt.Printf("Task failed: %v\n", err)
            }
            completed++
            if completed >= len(tasks) {
                break
            }
        }
        
        fmt.Printf("\nProcessing completed: %d tasks total, %d failures\n",
            completed, failures)
    }()
    
    // 等待所有任务完成
    wg.Wait()
    
    // 停止调度器
    scheduler.Stop()
    fmt.Println("Main: scheduler stopped")
}

让我们继续完成优先级控制的示例代码:

3.1 优先级控制流程图

4. 性能考虑

4.1 Select性能优化建议

  1. case数量控制
  • select中的case数量会影响性能
  • 建议控制在合理范围内(通常不超过5-10个)
  1. channel缓冲区
  • 适当使用带缓冲的channel可以提高性能
  • 避免频繁的阻塞和唤醒
  1. default分支使用
  • 合理使用default避免无谓的阻塞
  • 考虑轮询间隔,避免CPU空转

让我们实现一个性能优化的示例:

go 复制代码
package main

import (
    "fmt"
    "runtime"
    "sync"
    "sync/atomic"
    "time"
)

// 性能统计
type Stats struct {
    processed uint64
    dropped   uint64
    blocked   uint64
}

// 批处理器
type BatchProcessor struct {
    input     chan interface{}
    output    chan []interface{}
    done      chan struct{}
    stats     *Stats
    batchSize int
    maxWait   time.Duration
}

// 创建新的批处理器
func NewBatchProcessor(batchSize int, maxWait time.Duration) *BatchProcessor {
    return &BatchProcessor{
        input:     make(chan interface{}, batchSize*2),
        output:    make(chan []interface{}, batchSize),
        done:      make(chan struct{}),
        stats:     &Stats{},
        batchSize: batchSize,
        maxWait:   maxWait,
    }
}

// 启动处理
func (p *BatchProcessor) Start(workers int) {
    for i := 0; i < workers; i++ {
        go p.worker(i)
    }
    
    // 启动统计打印
    go p.printStats()
}

// 工作协程
func (p *BatchProcessor) worker(id int) {
    batch := make([]interface{}, 0, p.batchSize)
    timer := time.NewTimer(p.maxWait)
    defer timer.Stop()

    for {
        // 重置计时器
        if !timer.Stop() {
            select {
            case <-timer.C:
            default:
            }
        }
        timer.Reset(p.maxWait)

        // 优化的批处理逻辑
        for len(batch) < p.batchSize {
            select {
            case <-p.done:
                return
                
            case item := <-p.input:
                batch = append(batch, item)
                atomic.AddUint64(&p.stats.processed, 1)
                
            case <-timer.C:
                // 达到最大等待时间,处理当前批次
                if len(batch) > 0 {
                    p.processBatch(batch)
                    batch = batch[:0]
                }
                atomic.AddUint64(&p.stats.blocked, 1)
                continue
                
            default:
                // 如果输入队列为空且已有数据,立即处理
                if len(batch) > 0 {
                    p.processBatch(batch)
                    batch = batch[:0]
                }
                // 短暂休眠避免CPU空转
                runtime.Gosched()
                continue
            }

            // 批次满了就处理
            if len(batch) >= p.batchSize {
                p.processBatch(batch)
                batch = batch[:0]
            }
        }
    }
}

// 处理批次数据
func (p *BatchProcessor) processBatch(batch []interface{}) {
    // 创建副本避免数据竞争
    output := make([]interface{}, len(batch))
    copy(output, batch)
    
    // 尝试发送处理结果
    select {
    case p.output <- output:
        // 成功发送
    default:
        // 输出channel满了,增加丢弃计数
        atomic.AddUint64(&p.stats.dropped, uint64(len(batch)))
    }
}

// 提交数据
func (p *BatchProcessor) Submit(item interface{}) error {
    select {
    case p.input <- item:
        return nil
    case <-p.done:
        return fmt.Errorf("processor is stopped")
    default:
        atomic.AddUint64(&p.stats.dropped, 1)
        return fmt.Errorf("input channel full")
    }
}

// 获取输出通道
func (p *BatchProcessor) Output() <-chan []interface{} {
    return p.output
}

// 定期打印统计信息
func (p *BatchProcessor) printStats() {
    ticker := time.NewTicker(time.Second)
    defer ticker.Stop()
    
    var lastProcessed, lastDropped, lastBlocked uint64
    
    for {
        select {
        case <-p.done:
            return
        case <-ticker.C:
            processed := atomic.LoadUint64(&p.stats.processed)
            dropped := atomic.LoadUint64(&p.stats.dropped)
            blocked := atomic.LoadUint64(&p.stats.blocked)
            
            fmt.Printf("Stats - Processed: %d/s, Dropped: %d/s, Blocked: %d/s\n",
                processed-lastProcessed,
                dropped-lastDropped,
                blocked-lastBlocked)
            
            lastProcessed = processed
            lastDropped = dropped
            lastBlocked = blocked
        }
    }
}

// 停止处理器
func (p *BatchProcessor) Stop() {
    close(p.done)
}

func main() {
    // 创建批处理器
    processor := NewBatchProcessor(100, time.Millisecond*50)
    processor.Start(3)
    
    // 模拟高速数据提交
    var wg sync.WaitGroup
    for i := 0; i < 5; i++ {
        wg.Add(1)
        go func(id int) {
            defer wg.Done()
            for j := 0; j < 10000; j++ {
                data := fmt.Sprintf("Data-%d-%d", id, j)
                processor.Submit(data)
                time.Sleep(time.Microsecond * time.Duration(50+id*10))
            }
        }(i)
    }
    
    // 处理输出
    go func() {
        for batch := range processor.Output() {
            // 这里可以进行批量处理,比如写入数据库
            fmt.Printf("Received batch of size %d\n", len(batch))
        }
    }()
    
    // 等待提交完成
    wg.Wait()
    time.Sleep(time.Second) // 等待最后的处理完成
    
    // 停止处理器
    processor.Stop()
    fmt.Println("Main: processing completed")
}

4.2 性能优化要点

  1. 避免过度使用select
  • 只在必要的地方使用select
  • 考虑其他并发控制方式
  1. channel设计优化
  • 合理设置缓冲区大小
  • 避免频繁的channel创建和关闭
  1. goroutine管理
  • 控制goroutine数量
  • 实现优雅的退出机制
  1. 内存优化
  • 重用切片和对象
  • 避免不必要的内存分配

总结

核心要点

  1. Select实现原理
  • 随机选择机制
  • 阻塞和非阻塞模式
  • 多路复用特性
  1. 超时处理
  • 超时控制方法
  • 资源释放保证
  • 错误处理机制
  1. 优先级控制
  • 优先级实现方式
  • 任务调度策略
  • 公平性保证
  1. 性能优化
  • select使用建议
  • channel优化
  • 资源管理

怎么样今天的内容还满意吗?再次感谢观众老爷的观看,关注GZH:凡人的AI工具箱,回复666,送您价值199的AI大礼包。最后,祝您早日实现财务自由,还请给个赞,谢谢!

相关推荐
工业甲酰苯胺4 分钟前
聊一聊 C#线程池 的线程动态注入
java·开发语言·c#
zfenggo5 分钟前
c/c++ 无法跳转定义
c语言·开发语言·c++
向宇it15 分钟前
【从零开始入门unity游戏开发之——C#篇30】C#常用泛型数据结构类——list<T>列表、`List<T>` 和数组 (`T[]`) 的选择
java·开发语言·数据结构·unity·c#·游戏引擎·list
hakesashou20 分钟前
python怎么看矩阵维数
开发语言·python
daopuyun29 分钟前
GB/T34944-2017 《Java语言源代码漏洞测试规范》解读——安全功能
java·开发语言·安全
编程洪同学33 分钟前
Spring Boot 中实现自定义注解记录接口日志功能
android·java·spring boot·后端
qh0526wy40 分钟前
pyqt5冻结+分页表
开发语言·python·qt
hjxxlsx1 小时前
探索 C++ 自定义函数的深度与广度
开发语言·c++
罗政1 小时前
PDF书籍《手写调用链监控APM系统-Java版》第12章 结束
java·开发语言·pdf
匹马夕阳1 小时前
详细对比JS中XMLHttpRequest和fetch的使用
开发语言·javascript·ecmascript