并发编程实战(生产者消费者模型)

news2025/6/8 7:57:28

在并发编程中使用生产者和消费者模式能够解决绝大多数的并发问题。该模式通过平衡生产线程和消费线程的工作能力来提高程序整体处理数据的速度。

生产者和消费者模式:

在线程的世界中生产者就是产生数据的线程,而消费者则是消费数据的线程。在多线程开发中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完才能继续生产数据。同理,如果消费者处理速度很快,而生产者生产速度很慢,那么消费者就得等待生产者。为了解决这种生产消费能力不均衡的问题,便有了生产者和消费者模式。

在没有使用生产者和消费者模式之前,往往生产者和消费者都是高耦合的。生产者每次生产一个数据后的逻辑处理都依赖于消费者的处理能力。而采用这种模式之后通过一个容器来解决了强耦合的问题,生产者与消费者之间不再进行通信,所以生产者生产后的数据无需依赖于消费者进行处理而是直接扔到阻塞队列中,消费者同理。阻塞队列相当于一个缓冲区,平衡了生产者和消费者的处理能力。

纵观大多数的设计模式都会采用第三者来给双方进行解耦,工厂模式的第三方是工厂类,模板模式的第三方是模板类。。。因此在一些实际业务场景中我们也可以通过添加第三者的方式来将整个业务进行解耦的处理操作。

实际应用场景:

邮件分类:

在一个场景中假设我们需要从一个邮箱中将该邮箱的所有邮件进行分类处理。对于最简单的方法就是采用单线程不断轮询获取到该邮箱的所有邮件并且进行循环处理邮件将其进行。这种方式则最简单的方式但是这样做的缺点显而易见,如果邮箱中突然出现大量的邮件进行处理则会造成处理时间过长而造成性能下降。

那么我们想要提升处理吞吐量最简单的则是采用多线程的模式来进行处理。那么采用什么样方式处理最简单呢。提到多线程处理我们肯定是要保证同步的,那么有没有现成的线程安全的方案可以直接使用的呢,答案是阻塞队列。采用生产者消费者的模式来使用阻塞队列不仅能保证线程安全而且也提高了吞吐量更为重要的则是实现方式非常简单。

接下来我们将说一说设计思路,就如上图所示这是整个设计的架构图。生产者则是无论种类不断向阻塞队列里投放邮件,而第一个消费者则是取出邮件后进行分类处理投放到不同的阻塞队列中去,这个操作是cpu密集型操作而不是io密集型操作因此速度较快,而下面的几个消费者则是专门进行处理这种类型的邮件的。采用上述的方式不仅提高了吞吐量更为重要的是解耦并且实现简单。这就是生产者消费者模式。在实际的许多业务场景中使用这种方式进行处理则是很常见的。

线程池:

实际上我们最常使用的线程池它的内部本身就是采用的生产者消费者的模型机制。而这个模型设计的更加巧妙。

我们都知道线程池主要是由工作线程和任务队列以及任务组成的。在最常见的生产者消费者模型中则是生产者将任务丢给队列中,消费者从队列中取出。但是对于线程池则是如果有空闲线程则可以将任务直接交给空闲线程去处理这样做就省下了放到队列中的步骤。

异步线程池:

线程池固然好用但是有两个缺点:

1.线程池中的任务无法持久保存,如果主机宕机则会导致任务全部丢失

2.线程池只能处理本机的任务在集群中则无法去处理

因此对于以上缺点,异步线程池则能解决此类问题。结构如上图所示。

可以看出,当有任务来到的时候生产者将任务放入到数据库中,这次不再是阻塞队列中去。原因很简单:1.任务持久化处理,2.适用与分布式架构的模式。同时每个机器中开辟多个线程池,这多个线程池从数据库中取出任务,同时我们赋予任务状态来保证同步,状态值:创建,执行中,重试,挂起,中止,完成。

创建:这个状态则是生产者刚把任务放入数据库中等待消费者处理

执行中:消费者拿到任务后修改状态值表示这个任务以及被消费者处理中,其他消费者则在此过程中无法处理该任务

重试:消费者处理过程中发生异常情况则将此状态为设置为重试,根据不同任务的类型对应不同重试的策略

挂起:当前任务等待某个前置任务的完成之后才能执行本任务那么就需要将其设置为挂起,业务员自己设置挂起后的策略

中止:由于某种原因本任务则无需执行则会将其设置为中止状态

完成:完成了本任务的执行

那么异步线程池需要注意哪些地方呢

任务隔离:异步任务往往是有多种类型的,但是系统的资源是有限的。如果采用优先级的方式那么很有可能会造成某些高优先级的任务永远无法执行,因此我们采用的策略则是根据不同的任务我们采用不同的线程池进行处理,也就是任务类型分组处理,我们可以通过控制分组线程池的多少来进行进行控制处理的速率以及资源的部署。这样就不会造成某些任务永远无法处理的情况顶多是那些分配的资源少的任务类型处理速度上较慢。

重试策略:根据不同的任务类型设置不同的重试策略,有些任务可能要求实时性高。那么每次的重试间隔就会非常短,如果对实时性要求不高,可以采用默认的重试策略来对其进行重试。每个类型可以设置不同的重试次数

勿本机存储:对于不同机器上的线程池不要采用本机存储的方式因为整个项目采用的是集群部署,如果采用本机存储,某些后续任务可能有着上一个任务存储资源的存储路径,如果前置任务在机器A中完成那么后置任务将会无法找到这个资源

异步属性:对于所有任务都必须要带有任务的状态,名称,下次执行时间,执行次数,任务类型,报错类型等等任务属性。这样对于后续任务的进展将会有很大的帮助简化了不少的业务复杂度

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2403896.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

git小乌龟不显示图标状态解决方案

第一步 在开始菜单的搜索处,输入regedit命令,打开注册表。 第二步 在注册表编辑器中,找到HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers 这一项。 第三步 让Tortoise相关的项目排在前…

获取 OpenAI API Key

你可以按照以下步骤来获取 openai.api_key,用于调用 OpenAI 的 GPT-4、DALLE、Whisper 等 API 服务: 🧭 获取 OpenAI API Key 的步骤: ✅ 1. 注册或登录 OpenAI 账号 打开 https://platform.openai.com/ 使用你的邮箱或 Google/…

【Android基础回顾】五:AMS(Activity Manager Service)

Android 的 AMS(Activity Manager Service)是 Android 系统中的核心服务之一,负责管理整个应用生命周期、任务栈、进程和四大组件(Activity、Service、BroadcastReceiver、ContentProvider)的运行。它运行在系统进程 s…

pycharm中提示C++ compiler not found -- please install a compiler

1.最近用pycharm编译一个开源库,编译的依赖c compiler 2.单单使用pycharm编译,编译器报错C compiler not found – please install a compiler 3.需要在配置环境中引入对应库 4.从新编译后没有提示:C compiler not found – please install a compiler错误。

一站式直播工具:助力内容创作者高效开启直播新时代

近年来,随着互联网技术的不断进步和短视频、直播行业的爆发式增长,越来越多的企业和个人投入到直播电商、互动娱乐、在线教育等场景。直播运营过程中,涉及到数据统计、弹幕互动、流程自动化、内容同步等诸多环节。如何提升运营效率、减少人工…

以智能管理为基础,楼宇自控打造建筑碳中和新路径

在全球气候变化的严峻形势下,“碳中和”已成为各国发展的重要战略目标。建筑行业作为能源消耗与碳排放的“大户”,其运行阶段的能耗占全社会总能耗近40%,碳排放占比与之相当,实现建筑碳中和迫在眉睫。传统建筑管理模式下&#xff…

day029-Shell自动化编程-计算与while循环

文章目录 1. read 交互式初始化变量1.1 案例-安装不同的软件1.2 案例-比较大小 2. 计算2.1 bc2.2 awk2.3 expr2.4 let2.5 案例-计算内存的空闲率2.6 案例-检查域名过期时间和https整数过期时间 3. 循环3.1 循环控制语句3.2 for循环-c语言格式3.3 while循环3.3.1 案例-猜数字3.3…

Linux命令基础(2)

su和exit命令 可以通过su命令切换到root账户 语法:su [-] 用户名 -符号是可选的,表示是否在切换用户后加载环境变量,建议带上 参数:用户名,表示要切换的用户,用户名可以省略,省略表示切换到ro…

vue3 + vite实现动态路由,并进行vuex持久化设计

在后台管理系统中,如何根据后端返回的接口,来动态的设计路由呢,今天一片文章带你们解 1、在vuex中设置一个方法 拿到完整的路由数据 const state {routerList: []}; const mutations { dynameicMenu(state, payload) {// 第一步 通过glob…

学习路之php--性能优化

一、php周边优化 二、代码级优化 变量管理‌ 及时unset()释放大数组/对象,减少内存占用局部变量访问速度比全局变量快约2倍,优先使用局部变量大数组采用引用传递(&$var)避免内存 循环优化‌ 预计算循环次数: …

GC1808:高性能24位立体声音频ADC芯片解析

1. 芯片简介 GC1808 是一款24位立体声音频模数转换器(ADC),支持96kHz采样率,集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器,适用于家庭影院、蓝牙音箱等场景。 核心特性 高精度:24位分辨率,…

echarts使用graph、lines实现拓扑,可以拖动增加effect效果

options.js // import React from react // import * as echarts from echartsimport ./index.lessexport const useEchartsOptionFun ({ nodeDataList, getNodeLinksDataList, getLinesCoordsFun }) > {const option {title: {text: 拓扑关系图,top: top,left: center,}…

产品经理课程(九)

从需求到功能设计 (一)复习 产品规划:产品定位、阶段性计划 产品定位:产品画布(9个步骤;最重要的是先解决什么问题) (Roadmap)目标要素:时间、事项、里程碑…

从零开始开发纯血鸿蒙应用之网络检测

从零开始开发纯血鸿蒙应用 〇、前言一、认识 connection 模块1、获取默认网络2、获取网络能力信息3、解析网络能力信息3.1、NetCap3.2、NetBearType 二、实现网络检测功能1、申请权限2、获取默认网路的 NetCap 数组 三、总结 〇、前言 在之前的博文里,介绍了如何实…

向 AI Search 迈进,腾讯云 ES 自研 v-pack 向量增强插件揭秘

作者:来自腾讯云刘忠奇 2025 年 1 月,腾讯云 ES 团队上线了 Elasticsearch 8.16.1 AI 搜索增强版,此发布版本重点提升了向量搜索、混合搜索的能力,为 RAG 类的 AI Search 场景保驾护航。除了紧跟 ES 官方在向量搜索上的大幅优化动…

【win | docker开启远程配置】使用 SSH 隧道访问 Docker的前操作

在主机A pycharm如何连接远程主机B win docker? 需要win docker配置什么? 快捷配置-主机B win OpenSSH SSH Server https://blog.csdn.net/z164470/article/details/121683333 winR,打开命令行,输入net start sshd,启动SSH。 或者右击我的电脑&#…

股指期货波动一个点多少钱?

很多朋友在交易股指期货时,都会好奇一个问题:股指期货波动一个点,我的账户里到底是赚了还是亏了多少钱?要搞清楚这个问题,其实很简单,只需要了解两个关键信息:股指期货的“交易单位”&#xff0…

iOS、Android、鸿蒙、Web、桌面 多端开发框架Kotlin Multiplatform

Kotlin Multiplatform(简称 KMP)是 JetBrains 推出的开源跨平台开发框架 Kuikly 是腾讯开源的跨端开发框架,基于 Kotlin Multiplatform 技术构建,为开发者提供了技术栈更统一的跨端开发体验 KMP 不仅局限于移动端,它…

探索C++标准模板库(STL):String接口的底层实现(下篇)

前引:在C的面向对象编程中,对象模型是理解语言行为的核心。无论是类的成员函数如何访问数据,还是资源管理如何自动化,其底层机制均围绕两个关键概念展开:this指针与六大默认成员函数。它们如同对象的“隐形守护者”&am…

Flutter知识点汇总

Flutter架构解析 1. Flutter 是什么?它与其他移动开发框架有什么不同? Flutter 是 Google 开发的开源移动应用开发框架,可用于快速构建高性能、高保真的移动应用(iOS 和 Android),也支持 Web、桌面和嵌入式设备。。它与其他移动开发框架(如 React Native、Xamarin、原…