C/C++ 网络编程之关于多核利用问题
在 C/C++ 网络编程之中,多核利用分为以下几类:
1、一个链接一个线程,即传统且淘汰的 MTA 架构
形式:每次捕获链接,create_new_thread 一个子线程出来处理。
优点:开发简单,维护简单。
缺点:CPU及内存负载,成本高
2、一个链接一个进程,即传统且淘汰的 MPA 架构
形式:每次捕获链接,fork 一个子进程出来处理。
有点:可靠性高,主程式不易崩溃
缺点:CPU及内存负载,成本巨大且昂贵
3、把X个链接分配到一个工作线程上(利用线程池)
形式:
1、根据取模数分配到子线程
2、求子线程链接负载最小
3、队列线程FIFO分片轮替
即:队列拥有四个子线程的容量,每次需要捕获线程时,把顶部的线程弹出用于分配,并把使用后的线程压入队列尾部。
优点:性能高效,多核能效利用高,CPU上下文切换少
缺点:某个子线程,在一定的场景之中,必然会发生算术负载积压的问题,根据操作系统内核调度的特性,发生算术负载积压时,某个#CPU核会承担非常繁重的事务,这并不能达到,人们所期望的多核并行计算,同时且合理利用多个#CPU核。
举例:
A子线程被分配,1,2,3个链接,而这三个链接没有太多的数据需要进行交换,所以CPU负担为占用该U核的1% load 能效。
B子线程被分配,2个链接,但该链接存在严重的IO数据交换U能负载,导致该线程当前执行的U核被占用100% load 能效。
那么,假设该设备只有两个核心,程式只应用到101%的能效,并且不能提高吞吐量,事实上,若令两个U核,同时为所有的链接,真正的多核并行提供能效,这必定可以提高其的能效宽频IO吞吐量,而非像如此一般因为U核负载瓶颈,迫使性能不能真正被发挥出来。
4、多核并行消息/事件驱动状态机
形式:多个子线程,同时驱动一个消息/事件驱动状态机(MDSM/EDSM)
优点:性能高效,多核能效利用最大,CPU上下文切换少(略高)
缺点:具有一定的复杂性,工程维护成本偏高。
多个子线程,同时在一个消息/事件驱动状态机队列之中,捕获需要执行的任务(Task)并加以执行。
基于应用层的队列驱动下层实现,建议:
Windows:IOCP(完成端口)
Linux:EPOLL + ET(边缘触发),若内核大于等于 5.10.0 则应用采用 IO_URING(IO/U环)
MacOS X:Kqueue(K队列)
例如:
Network-IO 的读写行为,而得益于链接是线性状态,所以在多核计算时,同一个时间轮片调度之下,不会产生多个行为。
但人们仍旧,可以根据需要实现 strand(线),以确保某一个具体的事务,在多核并行处理时,保持时间轮片上的线性执行。
以下为 C/C++ 进行构建,允许单个网络链接,可被四个工作子线程相互调度执行。
妹妹苦爭鬥、玉碎瓦全登西樓。