RPC分布式通信(2)---四种典型式线程池(1)

基础讲解

固定式线程池 + 任务队列 核心概念讲解

简单来说:

  • 固定式线程池:提前创建固定数量的工作线程,线程一旦创建不会动态增减(区别于可扩容的缓存线程池),避免频繁创建 / 销毁线程的性能开销。

  • 任务队列:作为 "缓冲池",存放暂时来不及处理的任务,让线程池中的工作线程从队列中逐个取任务执行,避免请求直接被拒绝或线程数爆炸。

这一组合是 RPC 框架处理网络请求、异步回调、序列化 / 反序列化等任务的核心基础。


一、核心设计思想:"池化" + "缓冲"

在分布式系统(如 RPC)中,每收到一个远程调用请求就创建一个新线程处理,会带来两个致命问题:

  1. 线程创建 / 销毁的性能开销极大(涉及内核态 / 用户态切换、栈内存分配);
  2. 线程数无限制增长会耗尽系统内存,导致 OOM(内存溢出)或 CPU 上下文切换频繁,系统性能雪崩。

而 "固定式线程池 + 任务队列" 通过两个核心手段解决:

  1. 池化(线程池):提前创建 N 个线程并复用,线程运行期间不销毁,处理完一个任务就取下一个,直到线程池关闭;
  2. 缓冲(任务队列):所有待处理的任务先进入队列排队,工作线程从队列中 "消费" 任务,避免请求直接被丢弃,也避免线程数失控。

二、核心组成与工作流程

1. 核心组成部分

组件 作用 关键特性
任务队列(Task Queue) 存储待执行的任务(如 RPC 请求处理逻辑) 通常是阻塞队列(BlockingQueue),队列为空时线程阻塞等待,队列满时可拒绝 / 阻塞提交者
工作线程池(Fixed Thread Pool) 固定数量的工作线程 线程数 corePoolSize = maximumPoolSize(无扩容),线程空闲时不会销毁,持续监听队列
任务提交接口 向线程池提交任务的入口 支持提交 Runnable/Callable 任务,返回 Future(异步结果)
拒绝策略 任务队列满时的处理逻辑 如抛异常、丢弃任务、调用者自行执行、丢弃最老任务

2. 完整工作流程(以 RPC 请求处理为例)

具体步骤拆解:

  1. 任务提交:RPC 服务端接收到客户端的调用请求后,将 "处理这个请求" 的逻辑封装成一个任务对象,提交到线程池的任务队列;
  2. 线程监听:线程池中固定数量的工作线程会持续监听任务队列;
  3. 任务消费 :如果队列中有任务,空闲线程会取出任务并执行(执行过程包括反序列化参数、调用本地函数、序列化结果等);如果队列为空,线程会进入阻塞状态(不会占用 CPU 资源),直到队列中有新任务;
  4. 队列满处理 :如果任务提交速度远大于线程处理速度,任务队列会被填满,此时线程池会触发拒绝策略(比如抛异常,或让提交任务的线程自己执行);
  5. 线程复用:工作线程处理完一个任务后,不会销毁,而是回到 "监听队列" 的状态,等待下一个任务。

总结

关键点回顾

  1. 核心价值:固定式线程池 + 任务队列通过 "线程复用" 和 "任务缓冲",解决了 RPC 系统中线程频繁创建销毁、并发数失控的问题,提升稳定性和性能;
  2. 核心逻辑:任务先入队列,固定数量的工作线程从队列取任务执行,队列为空时线程阻塞,队列满时触发拒绝策略;
  3. 关键配置:线程数需根据任务类型(CPU/IO 密集型)调整,任务队列需设置长度限制,避免内存溢出。

代码实现

任务队列

cpp 复制代码
#ifndef SYNCQUEUE_HPP
#define SYNCQUEUE_HPP
#include<condition_variable>   
#include<mutex>
#include<queue>
#include<list>
#include<iostream>
using namespace std;
const int MaxTaskCount=200;
template<typename T>
class SyncQueue {
    // Class definition goes here
    private:
    std::list<T> queue;
    mutable std::mutex mtx;
    std::condition_variable notEmpty;
    std::condition_variable notFull;
    int maxTaskCount;
    bool stop;
    bool IsFull() const {
        bool full=queue.size() > maxTaskCount;
        if(full){
            std::cout<<"SyncQueue is full!"<<std::endl;
            return true;
        }
        return false;
    }
    bool IsEmpty() const {
        bool empty=queue.empty();
        if(empty){
            std::cout<<"SyncQueue is empty!"<<std::endl;
            return true;
        }
        return false;
    }
    template<typename F>
    void Add(F&& task){
        std::unique_lock<std::mutex> lock(mtx);
        notFull.wait(lock,[this](){return !IsFull() || stop;});
        if(stop) return;
        queue.push_back(std::forward<F>(task));
        notEmpty.notify_one();
    }
    // Member variables and methods
    public:
    SyncQueue(int maxSize=MaxTaskCount):maxTaskCount(maxSize),stop(false){}
    ~SyncQueue(){
        Stop();
    }
    void Put(const T& task){
        Add(task);
    }
    void Put(T&& task){
        Add(std::forward<T>(task));
    }
    // void Take(std::list<T>& tasks){
    //     std::unique_lock<std::mutex> lock(mtx);
    //     notEmpty.wait(lock,[this](){return !IsEmpty() || stop;});
    //     if(stop) return;
    //     queue=std::move(tasks);
    //     notFull.notify_all();
    // }
    void Take(T& task){
        std::unique_lock<std::mutex> lock(mtx);
        notEmpty.wait(lock,[this](){return !IsEmpty() || stop;});
        if(stop) return;
        task=std::move(queue.front());
        queue.pop_front();
        notFull.notify_one();
    }
    void Stop(){
        {
            std::lock_guard<std::mutex> lock(mtx);
            stop=true;
        }
        notEmpty.notify_all();
        notFull.notify_all();
}
    bool Empty() const{
        std::lock_guard<std::mutex> lock(mtx);
        return queue.empty();
    }
    bool Full() const{
        std::lock_guard<std::mutex> lock(mtx);
        return queue.size() >= maxTaskCount;
    }
    int Size() const{
        std::lock_guard<std::mutex> lock(mtx);
        return queue.size();
    }
    int Count() const{
        std::lock_guard<std::mutex> lock(mtx);
        return queue.size();
    }
    // Public interface
};
#endif

线程池代码

cpp 复制代码
#ifndef FIEXDTHREADPOOL_HPP
#define FIEXDTHREADPOOL_HPP
#include"SyncQueue.hpp"
#include<functional>
#include<list>
#include<thread>
#include<vector>
#include<atomic>

class FixedThreadPool {
    // Class definition goes here
     public:
    using task=std::function<void()>;
    private:
    //std::list<std::shared_ptr<std::thread>> tasks;
    std::vector<std::thread> threadgroup;
    SyncQueue<task> taskqueue;
    std::atomic_bool isrunning;
    std::once_flag flag;
    void Start(int threadNum){
        isrunning=true;
        for(int i=0;i<threadNum;++i){
            threadgroup.emplace_back([this](){this->Run();});
        }
    }
    void Run(){
        while(isrunning){
            task t;
            taskqueue.Take(t);
            if(!isrunning) break;
            if(t){
                t();
            }
        }
    }
    void stop(){
        taskqueue.Stop();
        for(auto& th:threadgroup){
            if(th.joinable()){
                th.join();
            }
        }
        threadgroup.clear();
    }
    public:
    FixedThreadPool(int threadNum=4,int maxTaskCount=200):taskqueue(maxTaskCount),isrunning(false){
       Start(threadNum);
    }
    ~FixedThreadPool(){
        Stop();
    }
    void Stop(){
        std::call_once(flag,[this]{stop();});
    }
    void AddTask(const task& t){
            taskqueue.Put(t);
    }
    void AddTask(task&& t){
            taskqueue.Put(std::forward<task>(t));
    }
};
#endif
相关推荐
不会c嘎嘎1 小时前
QT中的各种对话框
开发语言·qt
微露清风1 小时前
系统性学习C++-第二十四讲-智能指针的使用及其原理
java·c++·学习
我是一只小青蛙8881 小时前
手撕C++STL的list实现
开发语言·c++·list
顺心而行...1 小时前
安装 ubuntu 24.04 LTS 单系统教程
开发语言
I_belong_to_jesus1 小时前
LLVM后端入门8:Subtarget支持
c++·llvm
wenjianhai1 小时前
若依(RuoYi-Vue-Plus)框架使用WebSocket
java·若依
Coder_Boy_1 小时前
基于SpringAI的在线考试系统-核心模块的数据模型交互关系
java·数据库·人工智能·spring boot·交互
yaoxin5211231 小时前
295. Java Stream API - 选择适用于并行计算的 BinaryOperator
java·开发语言
We....1 小时前
SpringBoot 微服务拦截器与负载均衡实践
java·spring boot·微服务·负载均衡