多线程模型
简单接触一下对应与ASIO的俩种多线程模型。或者说,其实是俩种多线程设计上的思路。
IOServicePool
首先看到第一种模型。简单的说明一下这里的这种设计思路。对于一个服务器进程,我们将创建对应于机器的CPU核数的io_context数,每一个io_context都会被放在一个线程这种。每一个线程都独立的跑在一个CPU上,这样能够减少多个上下文之间的资源竞争。
对于每一个io_context,由于ASIO底层的设计,所以每个线程会存在一个任务调度队列,由于在高并发的情况下,对应的多个套接字可能会被绑定到一个上下文之中。此时就意味着将有一个上下文来进行这些线程的管理,对于运行在这个上下文中的所有套接字,其都是使用的本上下文中的事件队列。也就是说,对于所有的连接套接字中产生的请求,其都会注册到一个事件队列中。而在我们的该种多线程模式中,对应的事件处理线程是运行在同一个线程上的,此时会出现一个什么情况呢。
其实就类似于一种多生产者单消费者的模型。在这里,我们的每一个连接产生的套接字就是一个生成者,其生产的就是事件处理队列中需要处理的事件,我们的事件处理逻辑就是我们的消费者,负责进行我们的事件处理。那么这是你应该考虑到这种模型下的性能瓶颈,就是我们一个线程的运行速度是取决于我们的事件处理逻辑的,在事件处理的逻辑当中,我们可以将其视为一种耗时的操作,因为其是可能涉及到I/O操作的。而这时对应的接受请求则会不断的堆积。如果我们的事件处理逻辑十分的负责,那么我们一个线程对于全部的连接套接字的回复性能将会出现严重的性能劣化。
因此你应该也能想到这种多线程架构下的应用场景,其更适合对于那种事件处理逻辑相对简单的服务器架构,每个处理逻辑将不会导致过长的阻塞,来自客户端的请求可以由OS内核进行堆积。
模拟一下服务器的动作(抽离出一个线程)。假设现在该线程处于我们的任务逻辑中,而且每次的任务处理服务器都会一次性的清空当前的任务队列才进行退出。那么,在处理完我们当前的任务处理逻辑之后,对应的内核缓冲区将会堆积一些来自客户端的包,在处理完在之后我们服务器又可以转向对应的包的解析,由于我们假设对应的逻辑不会过于的复杂。所以这里的处理将会相对高效,服务器又可以在解析完这些包之后转向对应的事件处理逻辑。
接下来我们考虑一下在一种情况下的劣化。我们假设服务器存在一些处理相当耗时的逻辑,那么其在处理对应的事件时,整个线程由于是同步将会被阻塞,而如果这种事件过于的频繁,那么其会导致服务器的一个线程会浪费大量的事件在处理一些耗时的任务之上,其他的任务可能会出现饥饿的情况。
因此,这种模型非常适合下面场景:
- 请求处理逻辑较轻;
- 不涉及或尽量少涉及阻塞操作;
- 使用内核堆积数据能力(比如 TCP 接收缓冲区);
而对于复杂逻辑场景,则更推荐引入:
- 线程池执行复杂逻辑;
- 或采用 主线程处理 I/O,子线程执行任务处理逻辑 的模型(如下);
- 或者采用 Boost.Asio 支持的 协程/协作式多任务(如
awaitable
)模型。
接下来看到第二种线程模型的图,自行进行对应的性能分析和瓶颈分析吧
简单来说,这里是单个iocontext和多个线程之间的配合。
对于这种模型,我们的服务器的主逻辑运行在同一个线程中,该线程管理着所有的连接,其会处理所有的来自客户端的请求并压入到对应的任务队列中。在任务队列的处理中,会存在着多个处理线程从该队列中取出数据进行处理。那么你自然也能想到这种模型的应用场景,自然是在接受较轻松,任务处理较繁忙的场景上其会具有更好的性能。
本文中的一些逻辑比较混乱,不必太过在意,给出下面该表格请自行理解。
对比维度 | 每线程一个 io_context |
单个 io_context 多线程 |
---|---|---|
线程与上下文 | 每个线程绑定一个独立的 io_context |
所有线程共享一个 io_context |
线程间竞争 | 无竞争,每个 io_context 独立运行 |
存在竞争,线程争抢任务队列 |
负载分配 | 手动分配连接至不同 io_context |
所有连接都挂在同一个上下文 |
任务调度 | 每个线程单独调度自己上下文的任务 | 所有线程协作调度公共任务 |
事件处理逻辑复杂度 | 要求轻量、快速完成 | 可容忍复杂、耗时操作 |
饥饿问题 | 处理线程阻塞可能导致其上下文内连接饥饿 | 多线程可平衡负载,不易饥饿 |
扩展性 | 扩展线程需添加额外 io_context 与调度逻辑 |
扩展线程仅需绑定到同一个 io_context |
实现复杂度 | 高:需管理多个上下文和连接调度策略 | 低:逻辑清晰,易于维护 |
线程安全要求 | 相对较低(上下文隔离) | 高(共享资源需加锁) |
适合场景 | I/O密集,处理逻辑简单(如代理服务) | 业务逻辑复杂、重计算型服务(如 API 处理、数据库交互) |