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

异步处理优化:多线程线程池与消息队列的选择与应用

目录

一、异步处理方式引入

(一)异步业务识别

(二)明确异步处理方式

二、多线程线程池(Thread Pool)

(一)工作原理

(二)直面优缺点和适用场景

1.需要快速响应的异步任务

2.本地异步处理,任务不需要跨服务

3.有较好控制并发数的场景,避免过度占用资源

4.整合其优缺点

(三)业务代码实现

三、消息队列(MQ)

(一)工作原理

(二)直面优缺点和适用场景

1.分布式系统,多个服务之间需要解耦异步任务

2.高并发、高可靠性要求的任务处理

3.需要保证任务持久性、顺序性或可靠性的场景

4.整合其优缺点

(三)业务代码实现

四、异步方式选择

(一)任务是否需要跨服务或分布式处理

(二)任务的处理可靠性和持久性需求

(三)系统的并发处理能力和资源需求

(四) 延迟要求

(五)总结

五、总结


干货分享,感谢您的阅读!

在现代软件开发中,性能优化是每个开发者和团队不可回避的话题。随着系统复杂度的增加,尤其是面对高并发请求时,单纯依赖同步操作已经无法满足性能要求,导致接口响应缓慢、资源浪费等问题。为了提高系统的响应速度和可扩展性,异步处理成为一种有效的解决方案。异步处理将一些非核心逻辑的任务从主线程中剥离出来,通过并发执行,减少了主流程的等待时间,从而提升了用户体验和系统吞吐量。

本文将详细探讨常见的两种异步处理方式:多线程线程池消息队列(MQ)。通过分析它们的工作原理、优缺点以及适用场景,帮助读者更好地理解如何在实际开发中选择合适的异步处理方式。无论是本地并发处理,还是跨服务的任务解耦,合理选择异步策略将大大提升系统的性能和稳定性。

一、异步处理方式引入

在接口性能优化过程中,重新梳理业务逻辑,并识别哪些部分是核心逻辑,哪些部分是非核心逻辑,是非常重要的。如果把所有操作都放在接口中同步执行,可能会导致接口性能瓶颈,影响用户体验。因此,合理地将非核心逻辑异步化,可以显著提高系统的性能和响应速度。

(一)异步业务识别

假设在一个用户请求接口中,业务逻辑涉及到多个操作:业务操作、发站内通知、记录操作日志等。通常情况下,很多开发者可能会选择将这些操作放在一个同步执行的流程中,这样虽然简化了开发,但也不可避免地增加了接口响应时间,影响了整体性能。

具体来说:

  1. 核心逻辑:是指直接影响用户请求处理结果的部分,例如在这个例子中,业务操作是核心逻辑。
  2. 非核心逻辑:是指那些不影响用户请求直接响应的部分,例如发站内通知和记录操作日志,这些操作可以稍微延迟执行,对用户体验的影响较小。

在接口执行时,核心逻辑必须同步完成,但非核心逻辑则可以通过异步处理进行优化,从而不影响接口的响应时间。

(二)明确异步处理方式

所以为了优化性能,可以遵循以下原则:

  • 核心逻辑同步执行:对于需要立即返回用户请求的操作,必须同步执行并写入数据库,以确保数据一致性。
  • 非核心逻辑异步执行:对于不直接影响业务逻辑的操作,可以异步执行。这类操作可能包括:
    • 发送站内通知
    • 记录操作日志
    • 发送消息到消息队列(如 MQ)

异步化这些非核心操作,可以有效释放主线程,提高接口响应速度,同时保证后台任务的完成。常见的异步处理方式主要有两种:多线程线程池消息队列(MQ)

二、多线程线程池(Thread Pool)

(一)工作原理

多线程线程池的核心思想是将任务分配到多个线程中并发执行,从而减少任务等待时间。线程池预先创建一定数量的线程,通过管理这些线程来执行异步任务。线程池的管理由框架(如 Java 中的 ExecutorService)来处理,它负责线程的复用和销毁。

这部分的重点知识和使用可见:

  • Java线程池ThreadPoolExecutor背后的秘密与实践
  • 多线程编程全攻略:提升性能与线程安全的必备知识
  • 通用线程池封装与异步化实践:提升小红书发现页的响应速度

(二)直面优缺点和适用场景

多线程线程池是一种常见的并发执行异步任务的方式,通常用于以下场景:

1.需要快速响应的异步任务

多线程线程池适合用于响应时间要求较短的场景。由于线程池是预先创建好一定数量的线程,因此任务可以直接交给空闲的线程处理,避免了线程的频繁创建和销毁开销。这使得多线程线程池能够迅速响应并发任务,特别是对响应时间要求较高的业务,比如实时数据处理、事件驱动等。

2.本地异步处理,任务不需要跨服务

线程池主要适用于本地应用内的异步任务处理。例如,应用中某些计算密集型任务或需要并发处理的I/O操作,可以使用线程池在本地多核环境中实现并发。任务执行的速度比较快,且没有跨服务通信的需求,因此消息队列的引入会增加不必要的复杂度和延迟。

3.有较好控制并发数的场景,避免过度占用资源

线程池提供了对并发线程数的控制,可以避免过度创建线程导致资源耗尽。通过设置最大线程数,可以有效控制系统负载,避免线程过多导致的上下文切换开销过大,甚至系统崩溃。

在这类场景中,你可以根据负载情况调整线程池的大小。比如,使用 Java 中的 ExecutorService,可以通过设置核心线程数、最大线程数、线程存活时间等参数来精细化控制并发量和线程的生命周期。

4.整合其优缺点

优点

  • 响应时间短,适用于本地快速异步任务。
  • 可控的线程数量,避免过度占用系统资源。
  • 实现简单,适合单机应用。

缺点

  • 难以处理分布式任务和跨服务的异步通信。
  • 高并发情况下,线程池仍然可能遇到资源瓶颈或线程争用问题。

(三)业务代码实现

按照此思路,其实现方式如下图:

具体代码展示如:

// 创建一个固定大小的线程池
ExecutorService executorService = Executors.newFixedThreadPool(10); public void handleRequest(UserRequest request) {// 核心业务逻辑businessOperation(request);// 异步执行非核心逻辑executorService.submit(() -> sendNotification(request));  // 异步发送通知executorService.submit(() -> logUserAction(request));     // 异步记录操作日志
}

三、消息队列(MQ)

(一)工作原理

消息队列通过将任务封装为消息并发送到消息队列中,由后台消费者异步消费这些消息来完成任务。消息队列在异步处理任务时,将任务放入队列,任务的处理可以异步进行,队列通常会确保消息的顺序和可靠性。

背景知识可见:消息中间件知识整理(RabbitMQ、RocketMQ、ActiveMQ、Kafka、ZeroMQ、MetaMQ)

(二)直面优缺点和适用场景

消息队列(MQ)是一种用于异步任务处理的机制,常用于分布式系统中,具有以下应用场景:

1.分布式系统,多个服务之间需要解耦异步任务

消息队列是跨服务通信的理想选择。在分布式系统中,多个服务之间往往需要解耦,以减少直接依赖。如果任务的处理时间不确定,或者任务量过大,直接将任务交给另一服务处理可能会造成系统的负载过高或响应延迟。通过消息队列,任务会被异步放入队列中,由其他服务按需消费。

2.高并发、高可靠性要求的任务处理

在高并发场景下,消息队列能够很好地处理任务的高并发要求。生产者和消费者之间的解耦能够避免高并发情况下的性能瓶颈。此外,消息队列通常有持久化机制,可以保证消息在传输过程中的可靠性。如果一个服务失败或出现网络问题,消息仍然会被持久化,等到系统恢复后可以继续消费,确保任务不丢失。

3.需要保证任务持久性、顺序性或可靠性的场景

消息队列提供了消息的持久化、顺序消费等功能,这对于需要保证任务处理可靠性和顺序性的场景非常有用。例如,如果任务的处理顺序至关重要(如订单支付流程),消息队列可以确保消息按顺序被消费。常见的消息队列如 RabbitMQ、Kafka 都支持消息的持久化,能够确保即使系统崩溃或重启,也不会丢失消息。

4.整合其优缺点

优点:

  • 解耦多个系统或服务,适用于分布式环境。
  • 高并发下仍能保持良好的性能,避免资源竞争。
  • 提供可靠的任务持久性和顺序性保证。
  • 消息队列能够支持复杂的流量控制、重试机制和任务排队。

缺点:

  • 需要额外的基础设施支持(如部署消息队列服务)。
  • 延迟较高,响应时间可能较长。
  • 需要额外的操作和维护工作,配置复杂。

(三)业务代码实现

按照此思路,其实现方式如下图:

具体代码展示如:

public class UserService {// 假设是 MQ 的服务类private MessageQueueService messageQueueService; public void handleRequest(UserRequest request) {// 核心业务逻辑businessOperation(request);// 将异步任务放入消息队列messageQueueService.sendMessage("sendNotification", request);messageQueueService.sendMessage("logUserAction", request);}
}

四、异步方式选择

选择多线程线程池还是消息队列取决于你的业务需求和系统架构。选择考虑点:

(一)任务是否需要跨服务或分布式处理

  • 如果任务需要跨多个服务进行异步处理,推荐使用消息队列。它能够解耦服务,适应分布式系统的需求。
  • 如果所有任务都在同一台机器或同一应用中,且不涉及复杂的跨服务通信,可以使用线程池。

(二)任务的处理可靠性和持久性需求

  • 如果任务的可靠性要求高,必须确保任务不丢失或顺序性,消息队列是更好的选择。消息队列通常具有持久化和确认机制,能够保证任务的可靠传输。
  • 如果任务可以容忍失败或丢失,且不需要保证顺序性,线程池足以满足需求。

(三)系统的并发处理能力和资源需求

  • 如果需要较高并发且能够控制线程数量和资源消耗,线程池是一个合适的选择。线程池有更好的资源控制,适用于局部的并发处理。
  • 如果任务的处理量特别大,且并发量需要横向扩展,消息队列可以帮助系统水平扩展。

(四) 延迟要求

  • 如果任务需要即时处理(低延迟),线程池通常能提供更低的响应时间,因为它直接在线程池中执行任务。
  • 如果延迟要求较高,使用消息队列时可能会经历消息的排队和消费过程,延迟可能较大。

(五)总结

  • 线程池:适用于本地并发处理,快速响应且资源可控的场景。适合处理计算密集型任务、I/O 密集型任务或需要较高并发的场景。
  • 消息队列:适用于分布式系统,多个服务之间解耦、高并发、高可靠性的任务处理场景。适合任务的持久化、顺序性或需要跨服务异步处理的场景。

选择异步处理方式时,要综合考虑系统架构、任务的处理时间、并发量、可靠性要求等因素。如果是本地短时间内的异步任务,线程池足够;如果是分布式且需要高可靠性的任务,消息队列则更加合适。

五、总结

在处理异步任务时,选择合适的方式是优化系统性能的关键。多线程线程池适合用于本地任务的并发处理,尤其是当响应时间要求较低、资源可控、任务量不大的时候。它能够提高主线程的响应速度,但对于跨服务的任务或高并发场景,其局限性显现。另一方面,消息队列则更适合分布式系统,尤其是当任务需要跨多个服务、对可靠性和任务顺序性有较高要求时。它通过解耦服务、提供持久化存储、处理高并发任务,能够有效提升系统的可扩展性和可靠性。

因此,选择异步处理方式时需要根据实际需求进行权衡。如果任务是本地的、低延迟的且负载较轻,线程池是一个不错的选择;而如果任务需要分布式处理,或者对任务的可靠性、持久性要求较高,消息队列则更为合适。理解这两种异步方式的特点与适用场景,将帮助开发者在设计系统时做出更为明智的决策,从而实现性能的最优化。

相关文章:

异步处理优化:多线程线程池与消息队列的选择与应用

目录 一、异步处理方式引入 (一)异步业务识别 (二)明确异步处理方式 二、多线程线程池(Thread Pool) (一)工作原理 (二)直面优缺点和适用场景 1.需要快…...

Hadoop生态圈框架部署 伪集群版(一)- Linux操作系统安装及配置

文章目录 前言一、下载CentOS镜像1. 下载 二、创建虚拟机hadoop三、CentOS安装与配置1. 安装CentOS2. 配置虚拟网络及虚拟网卡2.1 配置虚拟网络2.2 配置虚拟网卡 3. 安装 SSH 远程连接工具 FinalShell3.1 简介3.2 下载和安装3.2.1 下载3.2.2 安装 3.3 查看动态ip地址3.4 使用Fi…...

Go的Gin比java的Springboot更加的开箱即用?

前言 隔壁组的云计算零零后女同事,后文简称 云女士 ,非说 Go 的 Gin 框架比 Springboot 更加的开箱即用,我心想在 Java 里面 Springboot 已经打遍天下无敌手,这份底蕴岂是 Gin 能比。 但是云女士突出一个执拗,非我要…...

pickle常见Error解决

1. pickle OverflowError: cannot serialize a bytes object larger than 4 GiB 进行pickle.dump时出现上述错误,可以加上“protocol4”参数。依据:https://docs.python.org/3/library/pickle.html#data-stream-format 2. pickle EOFError: Ran out of…...

认识Java数据类型和变量

数据类型分类 基本数据类型(8个): 整数型 byte 8位 short 16位 int 32位 long 64位 默认整数类型是int类型 小数型/浮点型 float【单精度32位】 double【双进度64位】 字符型 char 16位 只能表示单个字符 布尔型 boolean 1位 只能有两个值 true 【真】 false 【…...

Qt开发技巧(二十四)滚动部件的滑动问题,Qt设置时区问题,自定义窗体样式不生效问题,编码格式问题,给按钮左边加个图,最小化后的卡死假象

继续记录一些Qt开发中的技巧操作: 1.滚动部件的滑动问题 再Linux嵌入式设备上,有时候一个页面的子部件太多,一屏放不下是需要做页面滑动,可以使用“QScrollArea”控件,拖来一个“QScrollArea”控件,将子部件…...

SHELL----正则表达式

一、文本搜索工具——grep grep -参数 条件 文件名 其中参数有以下: -i 忽略大小写 -c 统计匹配的行数 -v 取反,不显示匹配的行 -w 匹配单词 -E 等价于 egrep ,即启用扩展正则表达式 -n 显示行号 -rl 将指定目录内的文件打…...

44.5.【C语言】辨析“数组指针”和“指针数组”

目录 1.数组指针 2.指针数组 执行结果 底层分析 1.数组指针 从语文的角度理解,"数组"修饰"指针".因此数组指针是指针 例如以下代码 #include <stdio.h> int main() {char a[5] { "ABCDE" };return 0;} 其中a就是数组指针,因为数…...

node.js基础学习-express框架-路由及中间件(十)

一、前言 Express 是一个简洁、灵活的 Node.js Web 应用框架。它基于 Node.js 的内置 HTTP 模块构建&#xff0c;提供了一系列用于构建 Web 应用程序和 API 的功能&#xff0c;使开发者能够更高效地处理 HTTP 请求和响应&#xff0c;专注于业务逻辑的实现。 其特点包括简单易用…...

使用MSYS搭建linux开发环境踩坑笔记

前言&#xff1a; 使用linux系统或虚拟机进行嵌入式linux开发是常规方法&#xff1b; 使用MSYS是用于尝鲜和研究。 由于windows和linux的差异&#xff0c;使用MSYS代替Linux虚拟机会遇到很多坑。 主要原因在于&#xff1a; 1. windows和linux文件系统的差异&#xff1a;win不…...

vue3+ts+vite+ElementPlus上传进度条实时更新(UPLoad和progress)。

需求&#xff1a; 上传文件时&#xff0c;展示进度条实时更新&#xff1a; 下面是代码片段: <!-- 添加媒体弹窗 -- 上传 --><el-dialog v-model"centerDialogVisible" title"媒体信息" width"700" :close-on-click-modal"false&qu…...

AspNet WebAPI 模型绑定问题

继承System.Web.Http.ApiController的Action的Model如果被[Serializable]定义&#xff0c;会导致Model的字段无法绑定。 Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll [Serializable] public class Model {public string id { get; set; } }public MyA…...

Android 图形系统之七:SurfaceFlinger

一. 引言 什么是 SurfaceFlinger&#xff1f;SurfaceFlinger 的核心作用和地位&#xff1f;为什么需要了解 SurfaceFlinger&#xff1f; 二. SurfaceFlinger 的基本概念 Surface 和 SurfaceFlinger 的关系SurfaceFlinger 与图形渲染&#xff08;OpenGL ES 和 Vulkan&#xf…...

14、鸿蒙学习——管理通知角标

针对未读的通知&#xff0c;系统提供了角标设置接口&#xff0c;将未读通知个数显示在桌面图标的右上角角标上。 通知增加时&#xff0c;角标上显示的未读通知个数需要增加。 通知被查看后&#xff0c;角标上显示的未读通知个数需要减少&#xff0c;没有未读通知时&#xff0…...

TongRDS分布式内存数据缓存中间件

命令 优势 支持高达10亿级的数据缓冲&#xff0c;内存优化管理&#xff0c;避免GC性能劣化。 高并发系统设计&#xff0c;可充分利用多CPU资源实现并行处理。 数据采用key-value多索引方式存储&#xff0c;字段类型和长度可配置。 支持多台服务并行运行&#xff0c;服务之间可互…...

[在线实验]-RabbitMQ镜像的下载与部署

镜像下载 docker的rabbitmq镜像资源-CSDN文库 加载镜像 docker load --input rabbitmq.tar 给镜像打标签 这里发现镜像名为none&#xff0c;需要给镜像重命名下 docker tag [镜像id] [新镜像名称]:[新镜像标签] docker tag ebaf409ffbe2 rabbitmq:management 运行镜像…...

Linux 系统文件描述符(File Descriptor)小白级介绍

1. 概述 Linux 遵循"一切皆文件"的理念。在 Linux 系统中&#xff0c;文件描述符是一个索引值&#xff08;非负整数&#xff09;&#xff0c;指向内核为每个进程所维护的该进程打开文件的记录表。 如上所述&#xff0c;每个进程都维护着一张文件描述符表。 文件描述…...

【Verilog】实验二 数据选择器的设计与vivado集成开发环境

目录 一、实验目的 二、实验环境 三、实验任务 四、实验原理 五、实验步骤 top.v mux2_1.v 一、实验目的 1. 掌握数据选择器的工作原理和逻辑功能。 2. 熟悉vivado集成开发环境。 3. 熟悉vivado中进行开发设计的流程。 二、实验环境 1. 装有vivado的计算机。 2. Sw…...

IDL学习笔记(三)OMI数据处理。hdf5文件读取,图像反转,GeoTiff区别,月季年均值计算提取输出,单位转换,运行时间计算

modis Level 2 grid 数据是全球格网化数据。一天的数据全在其中。 modis Level 1 和 2 数据是一景一景的影像。 IDL学习笔记&#xff08;三&#xff09;OMI数据处理 hdf5文件读取单位转换&#xff0c;输出hdf5数据集的图像&#xff0c;并检查图像经纬度是否正确&#xff0c;若错…...

深入浅出:PHP中的数据类型全解析

文章目录 引言理解数据类型标量类型整数 (integer)浮点数 (float)布尔值 (boolean)字符串 (string) 复合类型数组 (array)对象 (object)资源 (resource)NULL 特殊类型Callable强制类型转换 实战案例总结与展望参考资料 引言 在编程的世界里&#xff0c;数据类型是构建任何应用…...

要使用 OpenResty 创建一个接口,返回客户端的 IP 地址,并以 JSON 格式输出

要使用 OpenResty 创建一个接口&#xff0c;返回客户端的 IP 地址&#xff0c;并以 JSON 格式输出 要使用 OpenResty 创建一个接口&#xff0c;返回客户端的 IP 地址&#xff0c;并以 JSON 格式输出方案一解决方案&#xff08;openresty使用cjson&#xff09;说明&#xff1a;使…...

智慧油客:从初识、再识OceanBase,到全栈上线

今天&#xff0c;我们邀请了智慧油客的研发总监黄普友&#xff0c;为我们讲述智慧油客与 OceanBase 初识、熟悉和结缘的故事。 智慧油客自2016年诞生以来&#xff0c;秉持新零售的思维&#xff0c;成功从过去二十年间以“以销售产品为中心”的传统思维模式&#xff0c;转向“以…...

ClickHouse守护进程

背景描述 维护CK过程中&#xff0c;有时候会有CK OOM&#xff0c;并且CK自己没有自动拉起的情况出现&#xff1b;那么这个时候就需要守护进程&#xff0c;最初我不说了Supervisor来做守护进程&#xff0c;但是当我手动kill的时候发现并没有自动拉起。 解决方案 于是乎自己写…...

智能合约

06-智能合约 0 啥是智能合约&#xff1f; 定义 智能合约&#xff0c;又称加密合约&#xff0c;在一定条件下可直接控制数字货币或资产在各方之间转移的一种计算机程序。 角色 区块链网络可视为一个分布式存储服务&#xff0c;因为它存储了所有交易和智能合约的状态 智能合约还…...

SQL面试题——拼多多SQL面试题 求连续段的起始位置和结束位置

拼多多SQL面试题 求连续段的起始位置和结束位置 今天的题目来自拼多多,我们先看一下题目描述 有一张表ids记录了id,id不重复,但是会存在间断,求出连续段的开始位置和结束位置 +---+ | id| +---+ | 1| | 2| | 3| | 5| | 6| | 8| | 10| | 12| | 13| | 14| | 15| +--…...

玩《三角洲行动》遇到游戏运行故障是什么原因?游戏运行故障要怎么解决?预防游戏运行故障问题出现

《三角洲行动》游戏运行故障解析与解决方案&#xff1a;原因、解决与预防 在畅游《三角洲行动》这款充满挑战与激情的游戏时&#xff0c;玩家可能会遭遇各种游戏运行故障&#xff0c;如卡顿、闪退、无法启动等问题。我将结合自己丰富的经验和知识&#xff0c;为大家深入剖析《…...

基于灰色神经网络的订单需求预测

灰色神经网络&#xff08;Grey Neural Network, GNN&#xff09; 是将灰色系统理论与人工神经网络相结合的一种模型&#xff0c;旨在处理不完全信息和小样本问题。灰色神经网络利用灰色系统的预测优势和神经网络的学习能力&#xff0c;能够在信息不完整或数据不充分的情况下实现…...

记录学习《手动学习深度学习》这本书的笔记(三)

这两天看完了第六章&#xff1a;卷积神经网络&#xff0c;巧的是最近上的专业选修课刚讲完卷积神经网络&#xff0c;什么卷积层池化层听得云里雾里的&#xff0c;这一章正好帮我讲解了基础的知识。 第六章&#xff1a;卷积神经网络 6.1 从全连接层到卷积 在之前的学习中&…...

JS中递归函数的理解及展开运算符在递归种的运用理解

<!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><title>递归函数</title> </head> <body> <script>const list ["你好", "吃饭了吗",["好",[[&qu…...

人工智能学习用的电脑安装cuda、torch、conda等软件,版本的选择以及多版本切换

接触人工智能的学习三个月了&#xff0c;每天与各种安装包作斗争&#xff0c;缺少依赖包、版本高了、版本低了、不兼容了、系统做一半从头再来了。。。这些都是常态。三个月把单位几台电脑折腾了不下几十次安装&#xff0c;是时候总结一下踩过的坑和积累的经验了。 以一个典型的…...