4. 并发模型基础:多线程、多进程、异步
聊到并发,很多新手第一反应就是「开线程」。其实没那么简单。我在项目中踩过不少坑,发现选错并发模型,比写错加密算法还要命。今天咱们把三种主流模型掰开揉碎讲清楚。
说白了,并发就是让计算机同时干多件事。但怎么「同时」?这里有三种思路:多进程、多线程、异步。每一种都有自己的脾气秉性。
4.1 多进程:隔离第一,安全优先
多进程是最古老的并发方案。每个进程有独立的内存空间,一个挂了不影响别的。
核心概念:操作系统调度多个进程,每个进程有自己独立的地址空间、文件描述符、堆栈。
我在做支付加密模块时,就用了多进程架构。为什么?因为加密任务一旦崩溃,我不想它拖垮整个系统。
优点:
- 完全隔离,一个进程崩了,不影响大局
- 可以利用多核CPU,真的并行
- 安全性高,进程间数据不共享,天然防竞态
缺点:
- 创建销毁开销大,扛不住高频请求
- 进程间通信(IPC)很麻烦,性能瓶颈明显
- 内存占用多,每个进程都有独立堆栈
我的小技巧:加密场景如果每个请求计算量大(比如RSA2048签名),用进程池固定几个worker,避免频繁fork。
4.2 多线程:共享数据,但要小心锁
多线程共享进程的内存空间。这才是真正「轻量级」的并发。不过,共享也带来了麻烦——你得管好锁。
为什么加密场景要关注多线程?因为很多加密库(比如OpenSSL)内部用了线程局部存储。你如果乱开线程,可能踩到全局锁的坑。
举个例子,我曾经维护过一个签名服务,一开始用多线程,每个线程独立调用签名接口。结果压测时吞吐死活上不去。后来发现是OpenSSL的随机数生成器内部用了全局锁,线程一多,全在等锁。
解决办法?要么用独立的上下文(SSL_CTX),要么用异步方案。
| 特性 | 多进程 | 多线程 | 异步 |
|---|---|---|---|
| 内存开销 | 高 | 中 | 低 |
| 上下文切换 | 慢(内核态) | 较快(用户态) | 极快(无切换) |
| 数据共享 | 需IPC | 直接共享(需锁) | 回调传参 |
| 安全性 | 高(隔离) | 中(可能死锁) | 中(回调需谨慎) |
| 加密场景 | 长耗时计算 | 中等并发请求 | 高并发短请求 |
我曾经踩过的坑:多线程下,不要共享同一个加密上下文(Cipher Context)。每个线程要有独立副本,否则快得时候没问题,并发一上来,各种段错误和加解密错误就来了。
4.3 异步模型:事件驱动,高并发利器
异步模型,说白了就是一次只干一件事,但这件事不会等你。你在等网卡、等磁盘、等加密硬件时,CPU早就去处理别的事了。
我个人最喜欢用异步来处理加密请求转发。因为加密操作本身不慢,但网络I/O慢。异步能让你用单线程撑起上万连接。
核心机制:
- 事件循环(Event Loop)不断轮询
- 遇到I/O操作,注册回调,不阻塞
- I/O完成后,触发回调继续执行
你想想看,如果每个加密请求都开一个线程,那系统光切换线程就累死了。异步模式下,一个线程就够了,上下文切换几乎为零。
// 伪代码:异步加密请求处理
event_loop.run(async () => {
// 发起加密请求,不等待
const result = await crypto.encrypt(plaintext, key);
// 回调里处理结果
console.log(result);
});
我的经验:Node.js和Python的asyncio在处理大量短小的加密验证请求时,吞吐能是线程模型的2-3倍。但是要注意,如果加密操作本身需要大量CPU计算(比如哈希碰撞),那就别用异步了,容易把事件循环卡死。
4.4 该选哪个?看场景
没银弹。三种模型各有适用场景。我一般这么选:
- 长耗时加密计算(比如文件加密、大块数据签名):用多进程。一个worker跑一个任务,互不影响。
- 中等并发请求(比如每秒几百次签名):用多线程。注意线程安全就行。
- 超高并发短请求(比如每秒上万次验证):用异步。单线程撑全场。
还有混合方案。我在做加密网关时,外层用异步接收请求,内层用线程池处理实际的加密计算。这样既保证了高并发接收,又不让加密操作阻塞事件循环。
避坑指南:
- 多线程下,尽量使用线程池,不要无限制创建线程
- 多进程下,注意进程间通信开销,能用共享内存就用共享内存
- 异步下,小心回调地狱,可以用协程或者Promise链组织代码
- 无论哪种模型,加密上下文请务必独立管理
说到底,并发模型选型是你架构能力的第一道门槛。选对了,后面加解密调优就是锦上添花;选错了,再好的加密算法也发挥不出性能。