当前位置: 首页 > news >正文

linux网络编程11——线程池

1. 线程池

1.1 池化技术原理

池化技术

当一个资源或对象的创建或者销毁的开销较大时,可以使用池化技术来保持一定数量的创建好的对象以供随时取用,于是就有了池式结构。常见的池式结构包括线程池、内存池和连接池。

池化技术应用的前提条件主要包括三个,总结一下,以供记忆:

  1. 资源是可复用的。在计算机中,大部分资源都是可复用的,例如内存、线程、进程、tcp连接等。
  2. 资源可以长时间保存。像分配的内存块、已创建的线程、创建的TCP连接,都是可以长时间存在。
  3. 资源创建和销毁的开销较大。如动态内存分配,涉及系统调用和上下文切换,开销较大。

1.2 线程池原理

线程池

线程池是一种维持管理固定数量线程的池式结构。本文讲解了线程池的结构设计和实现。

下图是一个线程池的典型机构:

在这里插入图片描述

其中主要包括三个部件:

  • 生产者线程,是线程池的使用者,它通过向任务队列传递任务交给消费者线程执行。
  • 任务队列。是一个先进先出的队列,由于插入和删除元素都只需要在一段进行读写,因此临界区很短,比较高效。
  • 消费者线程,负责从任务队列中取出任务并执行。

下图是一个消费者线程的状态转换图。从图中可以看到,当任务队列不为空时,消费者线程就不断从中取出任务并执行,否则就会陷入等待态。

在这里插入图片描述

线程池的作用

  1. 性能优化,异步执行耗时任务,不过度占用核心线程,能够提高响应速度和性能。耗时任务可来自于:IO密集型任务(如网络IO和磁盘IO)、CPU密集型任务。
  2. 并发执行,充分利用多核,并发执行核心业务。
  3. 复用线程资源,减少创建和销毁线程的开销。

线程数量如何确定

线程数量取决于任务类型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,可以保证线程安全。具体是这样做的:

  1. 生产者线程提交任务时,先持有锁,然后检查任务队列是否已满,如果已满则陷入阻塞,否则将任务插入队列。然后通知消费者线程的等待队列。
  2. 消费者线程获取任务时,先持有锁,然后检查任务队列是否为空,如果为空则陷入阻塞,否则获取一个任务,然后通知生产者线程的等待队列。

线程池的关闭

线程池的关闭,需要先保证每个线程都被关闭,可以通过一个共享变量值的变化通知消费者线程和生产者线程,即设置一个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 池化技术原理 池化技术 当一个资源或对象的创建或者销毁的开销较大时&#xff0c;可以使用池化技术来保持一定数量的创建好的对象以供随时取用&#xff0c;于是就有了池式结构。常见的池式结构包括线程池、内存池和连接池。 池化技术应用的前提条件主要包括三…...

MySQL - 主从同步

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

基于微信小程序的安心陪诊管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…...

深入剖析iOS网络优化策略,提升App性能

一、引言 在当今移动互联网时代&#xff0c;iOS 应用的网络性能直接关系到用户体验。无论是加载速度缓慢、频繁的网络错误&#xff0c;还是高额的流量消耗&#xff0c;都可能导致用户流失。因此&#xff0c;iOS 网络优化成为开发者提升应用质量、增强用户满意度的关键环节。本文…...

游戏开发中常用的设计模式

目录 前言一、工厂模式二、单例模式三、观察者模式观察者模式的优势 四、状态模式状态模式的优势 五、策略模式策略模式的优势 六、组合模式七、命令模式八、装饰器模式 前言 本文介绍了游戏开发中常用的设计模式&#xff0c;如工厂模式用于创建对象&#xff0c;单例模式确保全…...

【PyCharm】远程连接Linux服务器

【PyCharm】相关链接 【PyCharm】连接Jupyter Notebook【PyCharm】快捷键使用【PyCharm】远程连接Linux服务器【PyCharm】设置为中文界面 【PyCharm】远程连接Linux服务器 PyCharm 提供了远程开发的功能&#xff0c;使得开发者可以在本地编辑代码或使用服务器资源。 下面将详…...

InVideo AI技术浅析(五):生成对抗网络

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

Spring自定义BeanPostProcessor实现bean的代理

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

【HF设计模式】06-命令模式

声明&#xff1a;仅为个人学习总结&#xff0c;还请批判性查看&#xff0c;如有不同观点&#xff0c;欢迎交流。 摘要 《Head First设计模式》第6章笔记&#xff1a;结合示例应用和代码&#xff0c;介绍命令模式&#xff0c;包括遇到的问题、采用的解决方案、遵循的 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 损失函数的实现与应用

引言 在深度学习中的分类问题中&#xff0c;类别不平衡问题是常见的挑战之一。尤其在面部表情分类任务中&#xff0c;不同表情类别的样本数量可能差异较大&#xff0c;比如“开心”表情的样本远远多于“生气”表情。面对这种情况&#xff0c;普通的交叉熵损失函数容易导致模型…...

AUTOSAR从入门到精通-自动驾驶测试技术

目录 前言 算法原理 测试场景定义与作用 测试场景要素 测试场景分类 场景信息提取与挖掘方法 自动驾驶感知测试分类 自动驾驶图像系统测试 自动驾驶激光雷达系统测试 自动驾驶融合感知系统测试 自动驾驶仿真测试 1. 功能安全 2. 预期功能安全 3. 软件测试 4.敏捷…...

优化大型语言模型的表达能力和依赖关系:理论

摘要 随着自然语言处理技术的发展&#xff0c;大型语言模型&#xff08;LLM&#xff09;已经成为理解和生成人类语言的强大工具。然而&#xff0c;如何有效提升这些模型的表达能力以及捕捉长距离依赖关系仍然是一个挑战。本文通过具体实例探讨了词表大小&#xff08;em_size&a…...

在Ubuntu下使用Wine运行MobaXterm并解决X服务器问题

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

【鸿蒙】0x02-LiteOS-M基于Qemu RISC-V运行

OpenHarmony LiteOS-M基于Qemu RISC-V运行 系列文章目录更新日志OpenHarmony技术架构OH技术架构OH支持系统类型轻量系统&#xff08;mini system&#xff09;小型系统&#xff08;small system&#xff09;标准系统&#xff08;standard system&#xff09; 简介环境准备安装QE…...

SW - 钣金零件保存成DWG时,需要将折弯线去掉

文章目录 SW - 钣金零件保存成DWG时&#xff0c;需要将折弯线去掉概述笔记备注END SW - 钣金零件保存成DWG时&#xff0c;需要将折弯线去掉 概述 如果做需要弯折的切割件&#xff0c;最好做成钣金零件。 最近做了几个小钣金(将钣金展开&#xff0c;建立新草图&#xff0c;在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、地理配准 一、应用场景 地理配准是数字化之前必须进行的一项工作。扫描得到的地图数据通常不包含空间参考信息&#xff0c;需要通过具有较高位置精度的…...

flutter在使用gradle时的加速

当我使用了一些过时的插件的时候&#xff0c;遇到了一些问题 比如什么namespace 问题等&#xff0c;因为有些插件库没有更新了&#xff0c;或者最新版本处于测试阶段 于是我就删除这些旧插件(不符合我要求的插件) 于是根据各论坛的解决方法去做了以下的工作 1:项目中删除了这…...

Python|GIF 解析与构建(5):手搓截屏和帧率控制

目录 Python&#xff5c;GIF 解析与构建&#xff08;5&#xff09;&#xff1a;手搓截屏和帧率控制 一、引言 二、技术实现&#xff1a;手搓截屏模块 2.1 核心原理 2.2 代码解析&#xff1a;ScreenshotData类 2.2.1 截图函数&#xff1a;capture_screen 三、技术实现&…...

【WiFi帧结构】

文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成&#xff1a;MAC头部frame bodyFCS&#xff0c;其中MAC是固定格式的&#xff0c;frame body是可变长度。 MAC头部有frame control&#xff0c;duration&#xff0c;address1&#xff0c;address2&#xff0c;addre…...

【论文阅读28】-CNN-BiLSTM-Attention-(2024)

本文把滑坡位移序列拆开、筛优质因子&#xff0c;再用 CNN-BiLSTM-Attention 来动态预测每个子序列&#xff0c;最后重构出总位移&#xff0c;预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵&#xff08;S…...

ABAP设计模式之---“简单设计原则(Simple Design)”

“Simple Design”&#xff08;简单设计&#xff09;是软件开发中的一个重要理念&#xff0c;倡导以最简单的方式实现软件功能&#xff0c;以确保代码清晰易懂、易维护&#xff0c;并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计&#xff0c;遵循“让事情保…...

【Java学习笔记】BigInteger 和 BigDecimal 类

BigInteger 和 BigDecimal 类 二者共有的常见方法 方法功能add加subtract减multiply乘divide除 注意点&#xff1a;传参类型必须是类对象 一、BigInteger 1. 作用&#xff1a;适合保存比较大的整型数 2. 使用说明 创建BigInteger对象 传入字符串 3. 代码示例 import j…...

蓝桥杯 冶炼金属

原题目链接 &#x1f527; 冶炼金属转换率推测题解 &#x1f4dc; 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V&#xff0c;是一个正整数&#xff0c;表示每 V V V 个普通金属 O O O 可以冶炼出 …...

视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)

前言&#xff1a; 最近在做行为检测相关的模型&#xff0c;用的是时空图卷积网络&#xff08;STGCN&#xff09;&#xff0c;但原有kinetic-400数据集数据质量较低&#xff0c;需要进行细粒度的标注&#xff0c;同时粗略搜了下已有开源工具基本都集中于图像分割这块&#xff0c…...

逻辑回归暴力训练预测金融欺诈

简述 「使用逻辑回归暴力预测金融欺诈&#xff0c;并不断增加特征维度持续测试」的做法&#xff0c;体现了一种逐步建模与迭代验证的实验思路&#xff0c;在金融欺诈检测中非常有价值&#xff0c;本文作为一篇回顾性记录了早年间公司给某行做反欺诈预测用到的技术和思路。百度…...

Unity UGUI Button事件流程

场景结构 测试代码 public class TestBtn : MonoBehaviour {void Start(){var btn GetComponent<Button>();btn.onClick.AddListener(OnClick);}private void OnClick(){Debug.Log("666");}}当添加事件时 // 实例化一个ButtonClickedEvent的事件 [Formerl…...

LOOI机器人的技术实现解析:从手势识别到边缘检测

LOOI机器人作为一款创新的AI硬件产品&#xff0c;通过将智能手机转变为具有情感交互能力的桌面机器人&#xff0c;展示了前沿AI技术与传统硬件设计的完美结合。作为AI与玩具领域的专家&#xff0c;我将全面解析LOOI的技术实现架构&#xff0c;特别是其手势识别、物体识别和环境…...