linux网络编程11——线程池
1. 线程池
1.1 池化技术原理
池化技术
当一个资源或对象的创建或者销毁的开销较大时,可以使用池化技术来保持一定数量的创建好的对象以供随时取用,于是就有了池式结构。常见的池式结构包括线程池、内存池和连接池。
池化技术应用的前提条件主要包括三个,总结一下,以供记忆:
- 资源是可复用的。在计算机中,大部分资源都是可复用的,例如内存、线程、进程、tcp连接等。
- 资源可以长时间保存。像分配的内存块、已创建的线程、创建的TCP连接,都是可以长时间存在。
- 资源创建和销毁的开销较大。如动态内存分配,涉及系统调用和上下文切换,开销较大。
1.2 线程池原理
线程池
线程池是一种维持管理固定数量线程的池式结构。本文讲解了线程池的结构设计和实现。
下图是一个线程池的典型机构:
其中主要包括三个部件:
- 生产者线程,是线程池的使用者,它通过向任务队列传递任务交给消费者线程执行。
- 任务队列。是一个先进先出的队列,由于插入和删除元素都只需要在一段进行读写,因此临界区很短,比较高效。
- 消费者线程,负责从任务队列中取出任务并执行。
下图是一个消费者线程的状态转换图。从图中可以看到,当任务队列不为空时,消费者线程就不断从中取出任务并执行,否则就会陷入等待态。
线程池的作用
- 性能优化,异步执行耗时任务,不过度占用核心线程,能够提高响应速度和性能。耗时任务可来自于:IO密集型任务(如网络IO和磁盘IO)、CPU密集型任务。
- 并发执行,充分利用多核,并发执行核心业务。
- 复用线程资源,减少创建和销毁线程的开销。
线程数量如何确定
线程数量取决于任务类型和cpu核心数量。
- cpu密集型:cpu核心数目
- io密集型: cpu核心数目 * (线程等待时间+cpu运算时间) / cpu运算时间
1.3 线程池的应用场景
1.3.1 nginx中的线程池
nginx中的线程池被用于处理文件IO。nginx主要有两个功能,分别是反向代理和提供静态文件资源。
在文件IO中,需要通过内核调用发送数据,涉及到内核态和用户态之间的上下文切换以及数据向内核缓冲区的传输,如果这些操作放在主线程执行将会导致一定的等待时间,减低了响应速度。
因此nginx使用线程池来分离耗时的操作,尤其时文件IO,避免其对主线程的干扰,从而提升 Nginx 的整体性能和响应效率。
1.3.2 redis中的线程池
Redis 默认情况下是单线程的,即它仅开启一个主线程来处理所有的请求。这也是 Redis 一直以来的设计理念,即使用单线程模型实现高性能。
不过,Redis 在 6.0 版本中引入了多线程支持,用于处理客户端的网络读写(如数据的读取、协议解析等),这可以提升在高并发环境下的网络 I/O 性能。
redis的线程池主要用于IO读写和协议解析,不负责执行操作。
1.4 线程池的实现
下面是一个使用C++11写的使用阻塞队列实现的线程池。
先看代码,然后进行讲解。
#include <stdio.h>
#include <chrono>
#include <condition_variable>
#include <functional>
#include <mutex>
#include <thread>
#include <queue>
#include <vector>typedef std::function<void(void)> Task;class ThreadPool
{
public:ThreadPool(size_t thread_count, size_t max_queue_size) :stop_(false), max_queue_size_(max_queue_size){for (size_t i = 0; i < thread_count; ++i){workers_.emplace_back(std::bind(&ThreadPool::worker_run, this));}}void enqueue(Task task){std::unique_lock<std::mutex> lock(mutex_);cond2_.wait(lock, [this] { return stop_ || queue_.size() < max_queue_size_; });if (stop_) return;queue_.emplace(std::move(task));cond1_.notify_one();}~ThreadPool(){{std::lock_guard<std::mutex> lock(mutex_);stop_ = true;}cond1_.notify_all();cond2_.notify_all();for (auto &thread : workers_){thread.join();}}private:void worker_run(){while (true){Task task;{// 出队操作std::unique_lock<std::mutex> lock(mutex_);cond1_.wait(lock, [this] { return stop_ || !queue_.empty(); });if (stop_) return;task = std::move(queue_.front());queue_.pop();cond2_.notify_one();}task();}}private:std::vector<std::thread> workers_; // 消费者线程std::mutex mutex_;std::condition_variable cond1_;std::condition_variable cond2_;bool stop_; // 是否停止运行size_t max_queue_size_; // 任务队列最大长度std::queue<Task> queue_; // 任务队列
};
内部主要组件
ThreadPool类中,在功能方面主要包括一个vector<thread>和一个queue<Task>,前者用来保存消费者线程,后者用来保存线程的任务。
另外,需要保证线程安全,因此需要一个mutex和两个条件变量,两个条件变量分别对应的消费者线程的等待队列和生产者线程的等待队列。
最后,stop_成员变量用来通知消费者线程结束执行,max_queue_size_成员变量用来指出queue_的最大尺寸。
对外接口enqueue
对外主要提供一个入队操作enqueue,在本实现中,设置了queue队列最大尺寸,因此该操作可能阻塞线程。
消费者线程主函数worker_run_
消费者线程的主要工作就是不断从任务队列中取出任务并执行。但任务队列为空时,需要消费者线程阻塞。
线程安全保证
通过std::mutex和std::unique_lock,以及std::condition_variable,可以保证线程安全。具体是这样做的:
- 生产者线程提交任务时,先持有锁,然后检查任务队列是否已满,如果已满则陷入阻塞,否则将任务插入队列。然后通知消费者线程的等待队列。
- 消费者线程获取任务时,先持有锁,然后检查任务队列是否为空,如果为空则陷入阻塞,否则获取一个任务,然后通知生产者线程的等待队列。
线程池的关闭
线程池的关闭,需要先保证每个线程都被关闭,可以通过一个共享变量值的变化通知消费者线程和生产者线程,即设置一个stop变量。
当需要关闭线程池时,设置stop为true,然后当生产者消费者线程看到stop为true时就不再阻塞,并且消费者线程会退出执行,而生产者线程为退出入队函数。
现在的问题在于,我们要保证stop的线程安全以及当stop的值发生变化时,其它线程能够即使看到。对于第一点,我们可以使用std::mutex和std::lock_guard来保证。对于第二点,我们可以让生产者和消费者线程在进入阻塞之前和退出阻塞之后都检查stop的值,如果stop值为true则直接return。
最后在关闭线程时,需要先更改stop的值为true,然后唤醒所有的等待中的线程。
1.5 总结
那么这个线程池就讲到这里。坦白说,这是一个非常基础的线程池,没有尝试使用无锁编程。线程池关闭可能被无限延迟(关闭一般是在程序结束运行时,所以一般问题不大)。另外对于任务类型,设计的也比较简单,没有考虑future和promise等,这个可以留给用户提供的task去自定义。
学习参考
学习更多相关知识请参考零声 github。
相关文章:

linux网络编程11——线程池
1. 线程池 1.1 池化技术原理 池化技术 当一个资源或对象的创建或者销毁的开销较大时,可以使用池化技术来保持一定数量的创建好的对象以供随时取用,于是就有了池式结构。常见的池式结构包括线程池、内存池和连接池。 池化技术应用的前提条件主要包括三…...

MySQL - 主从同步
1.主从同步原理: MySQL 主从同步是一种数据库复制技术,它通过将主服务器上的数据更改复制到一个或多个从服务器,实现数据的自动同步。 主从同步的核心原理是将主服务器上的二进制日志复制到从服务器,并在从服务器上执…...

基于微信小程序的安心陪诊管理系统
作者:计算机学姐 开发技术:SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等,“文末源码”。 专栏推荐:前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏:…...

深入剖析iOS网络优化策略,提升App性能
一、引言 在当今移动互联网时代,iOS 应用的网络性能直接关系到用户体验。无论是加载速度缓慢、频繁的网络错误,还是高额的流量消耗,都可能导致用户流失。因此,iOS 网络优化成为开发者提升应用质量、增强用户满意度的关键环节。本文…...
游戏开发中常用的设计模式
目录 前言一、工厂模式二、单例模式三、观察者模式观察者模式的优势 四、状态模式状态模式的优势 五、策略模式策略模式的优势 六、组合模式七、命令模式八、装饰器模式 前言 本文介绍了游戏开发中常用的设计模式,如工厂模式用于创建对象,单例模式确保全…...
【PyCharm】远程连接Linux服务器
【PyCharm】相关链接 【PyCharm】连接Jupyter Notebook【PyCharm】快捷键使用【PyCharm】远程连接Linux服务器【PyCharm】设置为中文界面 【PyCharm】远程连接Linux服务器 PyCharm 提供了远程开发的功能,使得开发者可以在本地编辑代码或使用服务器资源。 下面将详…...

InVideo AI技术浅析(五):生成对抗网络
一、特效生成 1. 工作原理 特效生成是计算机视觉中的高级应用,旨在通过算法生成高质量的视觉特效,如风格迁移、图像到图像的翻译等。InVideo AI 使用生成对抗网络(GAN)来实现这一功能。GAN 通过生成器和判别器两个网络的对抗训练,生成逼真的视觉特效。 2. 关键技术模型…...

Spring自定义BeanPostProcessor实现bean的代理
上文中:https://blog.csdn.net/qq_26437925/article/details/145241149 大致了解了spring aop的代理的实现,其实就是有个BeanPostProcessor代理了bean对象。 本文直接编写最简单的代码直观感受下 bean A: Service public class A {public A() {System.…...

【HF设计模式】06-命令模式
声明:仅为个人学习总结,还请批判性查看,如有不同观点,欢迎交流。 摘要 《Head First设计模式》第6章笔记:结合示例应用和代码,介绍命令模式,包括遇到的问题、采用的解决方案、遵循的 OO 原则、…...
Linux使用SSH连接GitHub指南
基础配置流程 步骤1:生成SSH密钥 打开终端:首先,打开你的Linux终端。 生成SSH密钥对:输入以下命令来生成一个新的SSH密钥对: ssh-keygen -t rsa -b 4096 -C "your_email@example.com"-t rsa:使用RSA加密算法生成密钥。-b 4096:密钥长度为4096位,增加安全性。…...
v2富文本框封装 @wangeditor/editor-for-vue
1 组件封装 <template><div class"editor-container"><div class"editor-wrapper"><Toolbarstyle"border-bottom: 1px solid #ccc":editor"editor":defaultConfig"toolbarConfig":mode"mode&quo…...
【分类】【损失函数】处理类别不平衡:CEFL 和 CEFL2 损失函数的实现与应用
引言 在深度学习中的分类问题中,类别不平衡问题是常见的挑战之一。尤其在面部表情分类任务中,不同表情类别的样本数量可能差异较大,比如“开心”表情的样本远远多于“生气”表情。面对这种情况,普通的交叉熵损失函数容易导致模型…...
AUTOSAR从入门到精通-自动驾驶测试技术
目录 前言 算法原理 测试场景定义与作用 测试场景要素 测试场景分类 场景信息提取与挖掘方法 自动驾驶感知测试分类 自动驾驶图像系统测试 自动驾驶激光雷达系统测试 自动驾驶融合感知系统测试 自动驾驶仿真测试 1. 功能安全 2. 预期功能安全 3. 软件测试 4.敏捷…...
优化大型语言模型的表达能力和依赖关系:理论
摘要 随着自然语言处理技术的发展,大型语言模型(LLM)已经成为理解和生成人类语言的强大工具。然而,如何有效提升这些模型的表达能力以及捕捉长距离依赖关系仍然是一个挑战。本文通过具体实例探讨了词表大小(em_size&a…...

在Ubuntu下使用Wine运行MobaXterm并解决X服务器问题
MobaXterm是一款功能强大的终端模拟器,集成了SSH客户端和X服务器,常用于远程服务器管理。在Ubuntu下,我们可以通过Wine运行MobaXterm,同时解决X服务器问题,实现远程图形界面转发。这对于需要远程使用ROS(如…...

【鸿蒙】0x02-LiteOS-M基于Qemu RISC-V运行
OpenHarmony LiteOS-M基于Qemu RISC-V运行 系列文章目录更新日志OpenHarmony技术架构OH技术架构OH支持系统类型轻量系统(mini system)小型系统(small system)标准系统(standard system) 简介环境准备安装QE…...

SW - 钣金零件保存成DWG时,需要将折弯线去掉
文章目录 SW - 钣金零件保存成DWG时,需要将折弯线去掉概述笔记备注END SW - 钣金零件保存成DWG时,需要将折弯线去掉 概述 如果做需要弯折的切割件,最好做成钣金零件。 最近做了几个小钣金(将钣金展开,建立新草图,在2…...

JAVA使用自定义注解,在项目中实现EXCEL文件的导出
首先定义一个注解 Retention(RetentionPolicy.RUNTIME) Target(ElementType.FIELD) public interface Excel {/*** 导出时在excel中排序*/int sort() default Integer.MAX_VALUE;/*** 导出到Excel中的名字.*/String name() default "";/*** 首行字段的批注*/String …...

【GIS操作】使用ArcGIS Pro进行海图的地理配准(附:墨卡托投影对比解析)
文章目录 一、应用场景二、墨卡托投影1、知识点2、Arcgis中的坐标系选择 三、操作步骤1、数据转换2、数据加载3、栅格投影4、地理配准 一、应用场景 地理配准是数字化之前必须进行的一项工作。扫描得到的地图数据通常不包含空间参考信息,需要通过具有较高位置精度的…...
flutter在使用gradle时的加速
当我使用了一些过时的插件的时候,遇到了一些问题 比如什么namespace 问题等,因为有些插件库没有更新了,或者最新版本处于测试阶段 于是我就删除这些旧插件(不符合我要求的插件) 于是根据各论坛的解决方法去做了以下的工作 1:项目中删除了这…...

C++_核心编程_多态案例二-制作饮品
#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为:煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例,提供抽象制作饮品基类,提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...
云计算——弹性云计算器(ECS)
弹性云服务器:ECS 概述 云计算重构了ICT系统,云计算平台厂商推出使得厂家能够主要关注应用管理而非平台管理的云平台,包含如下主要概念。 ECS(Elastic Cloud Server):即弹性云服务器,是云计算…...
FFmpeg 低延迟同屏方案
引言 在实时互动需求激增的当下,无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作,还是游戏直播的画面实时传输,低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架,凭借其灵活的编解码、数据…...

(二)原型模式
原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...

NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合
在汽车智能化的汹涌浪潮中,车辆不再仅仅是传统的交通工具,而是逐步演变为高度智能的移动终端。这一转变的核心支撑,来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒(T-Box)方案:NXP S32K146 与…...
SQL慢可能是触发了ring buffer
简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...

Linux 中如何提取压缩文件 ?
Linux 是一种流行的开源操作系统,它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间,使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的,要在 …...
git: early EOF
macOS报错: Initialized empty Git repository in /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/.git/ remote: Enumerating objects: 2691797, done. remote: Counting objects: 100% (1760/1760), done. remote: Compressing objects: 100% (636/636…...
comfyui 工作流中 图生视频 如何增加视频的长度到5秒
comfyUI 工作流怎么可以生成更长的视频。除了硬件显存要求之外还有别的方法吗? 在ComfyUI中实现图生视频并延长到5秒,需要结合多个扩展和技巧。以下是完整解决方案: 核心工作流配置(24fps下5秒120帧) #mermaid-svg-yP…...

Android写一个捕获全局异常的工具类
项目开发和实际运行过程中难免会遇到异常发生,系统提供了一个可以捕获全局异常的工具Uncaughtexceptionhandler,它是Thread的子类(就是package java.lang;里线程的Thread)。本文将利用它将设备信息、报错信息以及错误的发生时间都…...