Enterprise Rust/C++ · Technical Phone Screen

xAI Async vs Multithread:让出等待与真正并行

Enterprise Rust/C++ 初筛问 async 和多线程;解释任务调度、阻塞 I/O、CPU 任务、取消和两者组合。

题目重点:Enterprise Rust/C++ 初筛问 async 和多线程;解释任务调度、阻塞 I/O、CPU 任务、取消和两者组合。

题意与假设

这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。

  • async 指任务在 await I/O 等待点挂起,把执行线程让给其他可运行任务;不等同于自动创建新线程。
  • multithread 指多个操作系统线程可被调度到不同 CPU 核心;CPU 并行收益受语言 runtime 与锁/调度限制。
  • 测试负载分 I/O 等待与 CPU 计算两类;若 async 任务内有长时间同步阻塞,事件循环可能被卡住。

解题路线

  1. 先区分 concurrency 与 parallelism:单线程 async 可同时推进很多等待网络的任务,却同一瞬间只执行一个 CPU 指令流;多个线程可在多核上同时执行 CPU 任务。
  2. I/O 密集如成千连接:非阻塞 socket 与 async runtime 在等待时复用少量线程;任务状态、连接数与背压仍占内存,不保证无限并发。
  3. CPU 密集如排序/编码:交给受控线程池或进程池;若运行时限制 CPU 线程并行,应按语言能力处理。不要在单线程 event loop 直接做长 CPU 循环。
  4. 组合方案:async 接请求与调度,阻塞 I/O 或 CPU 工作放专用 bounded pool,完成后唤醒 awaiter;队列有容量与取消/超时传播,避免任务数无限膨胀。
  5. 比较调试和安全:线程需锁/消息传递防数据竞争,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/线程边界?
✓已复制微信号!