题目重点:Enterprise Rust/C++ 初筛问 async 和多线程;解释任务调度、阻塞 I/O、CPU 任务、取消和两者组合。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- async 指任务在 await I/O 等待点挂起,把执行线程让给其他可运行任务;不等同于自动创建新线程。
- multithread 指多个操作系统线程可被调度到不同 CPU 核心;CPU 并行收益受语言 runtime 与锁/调度限制。
- 测试负载分 I/O 等待与 CPU 计算两类;若 async 任务内有长时间同步阻塞,事件循环可能被卡住。
解题路线
- 先区分 concurrency 与 parallelism:单线程 async 可同时推进很多等待网络的任务,却同一瞬间只执行一个 CPU 指令流;多个线程可在多核上同时执行 CPU 任务。
- I/O 密集如成千连接:非阻塞 socket 与 async runtime 在等待时复用少量线程;任务状态、连接数与背压仍占内存,不保证无限并发。
- CPU 密集如排序/编码:交给受控线程池或进程池;若运行时限制 CPU 线程并行,应按语言能力处理。不要在单线程 event loop 直接做长 CPU 循环。
- 组合方案:async 接请求与调度,阻塞 I/O 或 CPU 工作放专用 bounded pool,完成后唤醒 awaiter;队列有容量与取消/超时传播,避免任务数无限膨胀。
- 比较调试和安全:线程需锁/消息传递防数据竞争,async 也可能有共享可变状态竞态、跨 await 锁持有和取消后资源清理问题。
手动走一遍
训练例:1000 个请求各等待远端 100ms,且本地 CPU 只需 1ms。单线程 async 可在等待期间切换,理论计算工作约 1 秒外加调度/网络瓶颈;逐请求独占线程则要管理 1000 线程。若每个请求本地计算 100ms,单线程 async 的 CPU 总工作约 100 秒,不会因 await 自动缩短;多核 worker pool 才可能并行。
规模与取舍
T 个并发 async 任务至少 O(T) 任务状态,线程池 P 个线程有 O(P) 栈/调度成本;总 CPU 工作不能因调度方式消失。延迟和吞吐取决于 I/O 等待比例、核数、runtime 与背压,题目无具体负载参数。
易错点与追问
容易失分的边界
- 说 async 等于多线程或等于并行执行 CPU 代码。
- 在事件循环调用阻塞 sleep/同步文件读,导致其他任务也停。
- 把上千线程当成上千核,忽略上下文切换与内存。
- 忽视 await 取消后锁、文件句柄或半完成事务的清理。
继续深挖
- async handler 必须调用阻塞库时怎样隔离?
- 何时在 Rust async 环境使用 spawn_blocking?
- 线程池太小与太大分别会怎样?
- 背压、超时与取消信号如何穿过 async/线程边界?
