
《AI时代的程序员修养》前两篇讲了程序和数据结构。这一篇进入另一个很容易被 AI 编程掩盖的问题:代码到底由谁执行,在哪里执行,什么时候让出 CPU,什么时候会把整个服务卡住。
很多并发 bug 不是因为代码太难,而是因为执行模型一开始没有说清楚。你让 AI “并发处理一批任务”,它可能写线程池;你让它“改成异步”,它可能只是在函数前面加 async;你让它“提高吞吐”,它可能多开几个 worker,却没有发现数据库连接池已经被打满。
执行模型不是底层八股。它决定系统能不能扛住慢接口、突发流量、CPU 计算、文件读写和外部服务抖动。
并发不是一个词
“并发执行”这句话太粗了。
它可能表示多个独立进程同时跑,也可能表示一个进程里多个线程抢时间片,还可能表示一个线程里用协程在等待 I/O 时切来切去。它们看起来都能“同时处理多个任务”,但成本、隔离性、共享状态和故障模式完全不同。
| 执行模型 | 常见场景 | 优点 | 风险 |
|---|---|---|---|
| 多进程 | Web worker、批处理 worker、CPU 密集任务 | 隔离强,单进程崩溃影响小,能利用多核 | 内存占用高,进程间通信成本高 |
| 多线程 | 阻塞 I/O 并发、后台任务、GUI 程序 | 共享内存方便,切换成本低于进程 | 竞态、死锁、线程池耗尽 |
| 协程 / async | 高并发网络 I/O、API 网关、爬取、长连接 | 单线程可承载大量连接,等待时切换便宜 | 一个阻塞调用就能卡住事件循环 |
| 事件驱动 | 消息消费、前端 UI、Node.js 服务、异步框架 | 适合大量短小事件和 I/O 回调 | 调用链分散,错误传播和上下文追踪复杂 |
| 批处理 | 数据同步、报表、离线任务 | 吞吐高,容易做批量优化 | 延迟高,失败恢复和断点续跑要设计 |
AI 很容易把这些模型混在一起。比如在 FastAPI 里生成一个 async def 接口,然后里面调用同步数据库驱动、同步 HTTP 客户端或者本地大文件读取。代码语法上是异步的,运行时却会把事件循环堵死。
所以写 prompt 时不要只说“异步处理”,要说清楚:
这是一个 async Web 接口,运行在单进程事件循环中。
请求路径不能执行阻塞 I/O。
数据库访问必须使用 async driver。
CPU 密集计算必须 offload 到进程池或独立 worker。
外部 HTTP 调用必须设置超时和并发上限。
这几句话比“帮我优化性能”有用得多。
进程:隔离很贵,但很可靠
进程是操作系统给程序划出的隔离空间。每个进程有自己的地址空间、文件描述符、环境变量、堆栈和运行状态。一个进程崩溃,通常不会直接踩坏另一个进程的内存。
Web 服务里常见的多进程模型,是一个 master 拉起多个 worker:
master
├── worker-1
├── worker-2
├── worker-3
└── worker-4
每个 worker 都能接请求。对 Python、Node.js 这类运行时来说,多进程也是绕开单进程 CPU 限制、利用多核的常见办法。
但进程不是免费的。
如果一个模型加载到内存需要 2GB,开 8 个进程可能就不是 2GB,而是接近 16GB,具体还取决于 copy-on-write、模型是否被修改、运行时内存分配方式。数据库连接也类似。每个进程一个连接池,4 个 worker、每个池 20 条连接,总连接数就是 80,不是 20。
让 AI 配 Web worker 时,很容易得到这种建议:
CPU 是 8 核,所以 worker 数设为 8。
这句话只对一小部分场景成立。更合理的估算


437

被折叠的 条评论
为什么被折叠?



