跳到正文

常见手写题与并发练习 ​

  • 状态:未准备
  • 适用方向:Go 全栈 / Go 后端
  • 最近复习:待填写
  • 下次复习:待安排

一句话回答 ​

手写题先约定输入、顺序、错误和取消语义,再写实现;并发题重点是容量与退出路径,不能只证明正常输入能跑通。

原理解释 ​

有界并发处理 ​

以下完整示例固定创建 worker,不按任务数无界创建 goroutine;全部任务由同一调用等待完成。fn 必须线程安全,若需及时取消也要响应 ctx。

go
package main

import (
    "context"
    "fmt"
    "sync"
)

func Run(ctx context.Context, workers int, jobs []int,
    fn func(context.Context, int) error) error {
    if workers <= 0 || fn == nil {
        return fmt.Errorf("invalid workers or function")
    }
    ctx, cancel := context.WithCancel(ctx)
    defer cancel()
    queue := make(chan int)
    var wg sync.WaitGroup
    var once sync.Once
    var firstErr error
    for i := 0; i < workers; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            for {
                select {
                case <-ctx.Done():
                    return
                case job, ok := <-queue:
                    if !ok { return }
                    if ctx.Err() != nil { return }
                    if err := fn(ctx, job); err != nil {
                        once.Do(func() { firstErr = err; cancel() })
                        return
                    }
                }
            }
        }()
    }
sendLoop:
    for _, job := range jobs {
        select {
        case <-ctx.Done():
            break sendLoop
        case queue <- job:
        }
    }
    close(queue) // 唯一生产者关闭,无并发发送者。
    wg.Wait()    // 等待后再读 firstErr。
    if firstErr != nil { return firstErr }
    return ctx.Err()
}

func main() {
    err := Run(context.Background(), 2, []int{1, 2, 3},
        func(ctx context.Context, n int) error {
            return ctx.Err() // 练习时替换为实际任务。
        })
    fmt.Println(err)
}

保证同时执行 fn 的数量不超过 workers;不保证结果顺序,也不保证取消瞬间再无任务进入 fn。首次记录的任务错误优先返回,否则返回 context 错误。若 fn 永久阻塞,Wait 仍会等待;不能靠外层取消强杀。

其他高频练习 ​

题目先约定必测边界
合并多个 channel输出何时关闭、如何取消零输入、输入提前关闭、下游停止
三协程轮流输出总次数与首个执行者0 次、最后一轮退出、无多余发送
LRU 缓存map + 双向链表,Get 是否更新顺序容量 0、更新已有 key、淘汰与并发
字符串反转字节、码点或完整字符空串、中文、组合字符
切片原地去重是否保序、是否允许改输入空输入、全重复、共享数组
限流器固定窗口、滑动窗口或令牌桶边界突发、时间源、并发更新

场景与边界 ​

以上是教学实现,不含结果汇总、panic 恢复、持久化重试和线上指标;需要时按业务扩展。错误、取消和完成同时发生时先定义允许的行为,避免写出无法保证的承诺。

项目中的应用 ​

结合 SimulSpeak 模型调用思考不同会话的并发上限;不代表项目目前使用此示例。

常见追问 ​

  • 为什么不用每个任务先 go 再抢信号量? 那仍会创建大量等待 goroutine,固定 worker 更直接控制数量。
  • 怎么保序? 为输入编号并按序汇总,说明慢任务导致的队首等待与缓冲上限。
  • 如何验证? 空任务、非法 worker、首次错误、预先取消、处理中取消;用原子计数记录同时在途峰值,任务阻塞用信号协调。

参考资料 ​

理解机制,讲清取舍,用复盘检验掌握。