ZLToolKit 源码分析(四):TaskExecutor 与 WorkThreadPool 任务调度
上篇分析了 ThreadPool 的底层实现,本文聚焦上层调度:TaskExecutorGetterImp 的负载均衡策略、WorkThreadPool 的双池设计,以及 ZLToolKit 如何实现"IO 线程"与"工作线程"的职责分离。
1. 线程池体系总览
TaskExecutorInterface (接口) └─ TaskExecutor (CPU 负载 + thread_local) ├─ ThreadPool (基础线程池) │ └─ EventPoller (IO 事件轮询) │ └─ EventPollerPool (IO 线程池单例) └─ WorkThreadPool (工作线程池单例)ZLToolKit 将线程分为两类:
| 线程类型 | 池 | 职责 | 数量 |
|---|---|---|---|
| IO 线程 | EventPollerPool | epoll 事件循环、Socket 读写 | CPU 核数 |
| Worker 线程 | WorkThreadPool | 耗时计算、协议解析、媒体处理 | CPU 核数 |
2. TaskExecutorGetterImp — 执行器获取器
2.1 核心接口
classTaskExecutorGetterImp{public:// 获取第一个执行器TaskExecutor::PtrgetFirstExecutor();// 获取负载最低的执行器(轮转 + 负载加权)TaskExecutor::PtrgetExecutor();// 获取执行器数量size_tgetExecutorSize()const;// 遍历所有执行器voidforEach(constfunction<void(constTaskExecutor::Ptr&)>&cb);protected:vector<TaskExecutor::Ptr>_executors;atomic<size_t>_loop_index{0};};2.2 getExecutor — 负载均衡算法
TaskExecutor::PtrTaskExecutorGetterImp::getExecutor(){autosize=_executors.size();if(size==0)returnnullptr;if(size==1)return_executors[0];// 策略:轮转 + 负载均衡// 1. 从轮转位置开始// 2. 找到负载最低的执行器// 3. 如果有负载为 0 的,直接返回(无锁快速路径)TaskExecutor::Ptr executor_min_load;floatmin_load=1.0f;for(size_t i=0;i<size;++i){autoidx=(_loop_index++)%size;auto&executor=_executors[idx];autoload=executor->