性能优化实战使用CountDownLatch

1.分析问题

原程序是分页查询EventAffinityScoreDO表的数据,每次获取2000条在一个个遍历去更新EventAffinityScoreDO表的数据。但是这样耗时比较慢,测试过30万的数据需要2小时

  private void eventSubjectHandle(String tenantId, String eventSubject) {// 查询eventAffinityScoreDO表,更新时间小于今天的(今天更新过的不更新)final Integer pageSize = 2000;PageResult<EventAffinityScoreDO> groupPag =eventAffinityScoreDbService.findByTenantIdAndTimePage(tenantId, eventSubject, 1, pageSize);Integer pages = groupPag.getPages();Integer pageNum = groupPag.getPageNum();while (pages >= pageNum) {if (pageNum > 1) {groupPag =eventAffinityScoreDbService.findByTenantIdAndTimePage(tenantId, eventSubject, 1, pageSize);}List<EventAffinityScoreDO> list = groupPag.getList();forEventAffinityScore(tenantId, eventSubject, list);if (list.size() < pageSize) {break;}pageNum++;}}private void forEventAffinityScore(String tenantId, String eventSubject, List<EventAffinityScoreDO> eventAffinityScoreDOS) {eventAffinityScoreDOS.forEach((eventAffinityScoreDO) -> {//更新EventAffinityScoreDO表数据updateOrAddAffinity(tenantId,eventAffinityScoreDO.getChatLabsId(),eventAffinityScoreDO.getEconomyId(),eventAffinityScoreDO.getAttributeValue(),eventSubject,eventAffinityScoreDO.getAttributeName());});}

单个线程一个个遍历去更新表数据太慢了,我想把2000的数据分成多份,每份200条,可以分成10份。每份用一个线程去跑。这样跑2000的时间就大大缩短。大概等于跑200个数据的时间。
这里想到使用CountDownLatch

2.知识点CountDownLatch

CountDownLatch 是 Java 中的一个并发工具类,用于在多线程环境中控制线程的执行顺序。它允许一个或多个线程等待其他线程完成操作后再继续执行。
CountDownLatch 的构造方法接受一个整数作为参数,表示需要等待的线程数量。当一个线程完成了自己的任务后,可以调用 countDown() 方法来将计数器减1。当计数器的值变为0时,所有等待的线程都会被释放,可以继续执行。

3.解决问题

我们使用Lists.partition,把2000的集合拆分成每份200的小份,共10分。
CountDownLatch countDownLatch = new CountDownLatch(partition.size())设置CountDownLatch需要等待的线程数为拆分后的份数partition.size(),也就是10份
countDownLatch.countDown(); 每跑完一份计数器减一
countDownLatch.await();计数器减完主程序开始执行,继续循环后面的2000份

 private void eventSubjectHandle(String tenantId, String eventSubject)throws InterruptedException {// 查询eventAffinityScoreDO表,更新时间小于今天的(今天更新过的不更新)final Integer pageSize = 2000;PageResult<EventAffinityScoreDO> groupPag =eventAffinityScoreDbService.findByTenantIdAndTimePage(tenantId, eventSubject, 1,pageSize);Integer pages = groupPag.getPages();Integer pageNum = groupPag.getPageNum();while (pages >= pageNum) {if (pageNum > 1) {groupPag =eventAffinityScoreDbService.findByTenantIdAndTimePage(tenantId, eventSubject, 1, pageSize);}List<EventAffinityScoreDO> list = groupPag.getList();//Lists.partition把list进行拆分,没份200个List<List<EventAffinityScoreDO>> partition = Lists.partition(list, 200);//设置需要等待的线程数量,就是我们的集合大小CountDownLatch countDownLatch = new CountDownLatch(partition.size());for (List<EventAffinityScoreDO> eventAffinityScoreDOS : partition) {eventSubjectExecutorPool.execute(() -> {try {forEventAffinityScore(tenantId, eventSubject, eventAffinityScoreDOS);} catch (Exception e) {log.info("AutoAffinityJob updateAffinityByEventSubject error tenantId:{},eventSubject:{}",tenantId,eventSubject,e);}//每处理完200份计数器减一countDownLatch.countDown();});}//计数器减完主程序开始执行,继续循环后面的2000份countDownLatch.await();if (list.size() < pageSize) {break;}pageNum++;}}private void forEventAffinityScore(String tenantId, String eventSubject, List<EventAffinityScoreDO> eventAffinityScoreDOS) {eventAffinityScoreDOS.forEach((eventAffinityScoreDO) -> {// 根据生态中事件属性属性值更新or新增影响到的内容亲和力updateOrAddAffinity(tenantId,eventAffinityScoreDO.getChatLabsId(),eventAffinityScoreDO.getEconomyId(),eventAffinityScoreDO.getAttributeValue(),eventSubject,eventAffinityScoreDO.getAttributeName());});}

这里需要注意的是如果线程池设置的太小,会导致触发拒绝策略。如果触发了拒绝策略countDownLatch.countDown()就不会执行了。就会导致countDownLatch.await()一直等待。所以这里我把线程池的队列设置的很大Integer.MAX_VALUE,这样不会触发拒绝策略。因为我们最多就10个线程,也不会导致出现OOM

@Configuration
@Slf4j
public class CalculateAffinityThreadPool {@Bean(name = "eventSubjectExecutorPool")public ExecutorService eventSubjectExecutorPool() {int poolSize = ThreadExecutorUtils.getNormalCoreSize();return ThreadExecutorUtils.createNormalThreadPool(poolSize,poolSize,0L,TimeUnit.MILLISECONDS,Integer.MAX_VALUE,"eventSubject-pool",false);}}

经过测试跑30万的数据只需要20分钟了。

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

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

相关文章

3.6+铁死亡+WGCNA+机器学习

今天给同学们分享一篇3.6铁死亡WGCNA机器学习的生信文章“Identification of ferroptosis related biomarkers and immune infiltration in Parkinsons disease by integrated bioinformatic analysis”&#xff0c;这篇文章于2023年3月14日发表在BMC Med Genomics期刊上&#…

队列的使用以及模拟实现(C++版本)

&#x1f388;个人主页:&#x1f388; :✨✨✨初阶牛✨✨✨ &#x1f43b;强烈推荐优质专栏: &#x1f354;&#x1f35f;&#x1f32f;C的世界(持续更新中) &#x1f43b;推荐专栏1: &#x1f354;&#x1f35f;&#x1f32f;C语言初阶 &#x1f43b;推荐专栏2: &#x1f354;…

C运算符和控制语句

几乎每一个程序都需要进行运算&#xff0c;对数据进行加工处理&#xff0c;否则程序就没有意义了。要进行运算&#xff0c;就需规定可以使用的运算符。 C语言的运算符范围很宽&#xff0c;把除了控制语句和输人输出以外的几乎所有的基本操作都作为运算符处理。 运算符分类1 除…

QToolButton几个小知识点总结

QToolButton设置图标及更改图标大小 QToolButton btn;btn.setIconSize(QSize(35,35));//更改图标大小btn.setIcon(QIcon(":/images/screen.png"));//设置图标QToolButton设置图标和文字显示格式 enum ToolButtonStyle {ToolButtonIconOnly, //只显示图标&#xff08;…

正太分布核函数

正太分布概率密度推导&#xff1a; 设 I ∫ − ∞ ∞ 1 2 π e − x 2 2 d x I \int _{-\infty}^{\infty}\frac{1}{\sqrt{2\pi}}e^{-\frac{x^2}{2}}dx I∫−∞∞​2π ​1​e−2x2​dx 则&#xff1a; I 2 ∫ − ∞ ∞ 1 2 π e − x 2 2 d x ∫ − ∞ ∞ 1 2 π e −…

likeadmin和fastapi的bug

以下内容写于2023年8月11日 bug 1 请求体 - 多个参数 - FastAPI (tiangolo.com)中“请求体中的单一值”处&#xff0c;选python3.6&#xff0c;接口示例代码是 from typing import Unionfrom fastapi import Body, FastAPI from pydantic import BaseModel from typing_exte…

Spring Boot中配置文件介绍及其使用教程

目录 一、配置文件介绍 二、配置简单数据 三、配置对象数据 四、配置集合数据 五、读取配置文件数据 六、占位符的使用 一、配置文件介绍 SpringBoot项目中&#xff0c;大部分配置都有默认值&#xff0c;但如果想替换默认配置的话&#xff0c;就可以使用application.prop…

从零手搓一个【消息队列】项目设计、需求分析、模块划分、目录结构

文章目录 一、需求分析1, 项目简介2, BrokerServer 核心概念3, BrokerServer 提供的核心 API4, 交换机类型5, 持久化存储6, 网络通信7, TCP 连接的复用8, 需求分析小结 二、模块划分三、目录结构 提示&#xff1a;是正在努力进步的小菜鸟一只&#xff0c;如有大佬发现文章欠佳之…

阿里云效自动构建python自动测试脚本

之前一直用的是jenkins自动构建自动化脚本&#xff0c;因为现在的公司统一在阿里云效的流水线上做代码的管理&#xff0c;构建&#xff0c;要求自动化测试也在上面自动构建&#xff0c;故而学习了一下。为自己做一个记录&#xff0c;也给有需要的朋友做一个参考。 1. 新建流水…

设计模式4、建造者模式 Builder

解释说明&#xff1a;将一个复杂对象的构建与它的表示分离&#xff0c;使得同样的构建过程可以创建不同的表示 UML 结构图&#xff1a; 抽象建造者&#xff08;Builder&#xff09;&#xff1a;这个接口规定要实现复杂对象的那些部分的创建&#xff0c;并不设计具体部件对象的创…

在MySQL中使用VARCHAR字段进行日期筛选

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

ROS2 从头开始​​:第6部分 - ROS2 中的 DDS,用于可靠的机器人通信

一、说明 在这篇文章中,我们将重点关注 ROS 2的通信栈DDS,其中这是介于管理节点通信与控制节点通信环节,是上位机决策体系与下位机的控制体系实现指令-执行-反馈的关键实现机制。 二、ROS工程的概念框架 现代机器人系统非常复杂,因为需要集成各种类型的传感器、执行器和其…

Composition API(常用部分)

1. Composition API(常用部分) 文档: ​ https://composition-api.vuejs.org/zh/api.html 1) setup 新的option, 所有的组合API函数都在此使用, 只在初始化时执行一次函数如果返回对象, 对象中的属性或方法, 模板中可以直接使用2) ref 作用: 定义一个数据的响应式语法: cons…

No148.精选前端面试题,享受每天的挑战和学习

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入…

MySQL到TiDB:Hive Metastore横向扩展之路

作者&#xff1a;vivo 互联网大数据团队 - Wang Zhiwen 本文介绍了vivo在大数据元数据服务横向扩展道路上的探索历程&#xff0c;由实际面临的问题出发&#xff0c;对当前主流的横向扩展方案进行了调研及对比测试&#xff0c;通过多方面对比数据择优选择TiDB方案。其次分享了整…

查看react内置webpack版本的方法

yarn list --pattern webpack npm ls --pattern webpack

Java基础---第六篇

系列文章目录 文章目录 系列文章目录一、、Java创建对象有几种方式&#xff1f;二、有没有可能两个不相等的对象有相同的hashcode三、深拷贝和浅拷贝的区别是什么? 一、、Java创建对象有几种方式&#xff1f; java中提供了以下四种创建对象的方式: new创建新对象 通过反射机制…

Python3操作SQLite3创建表主键自增长|CRUD基本操作

Win11查看安装的Python路径及安装的库 Python PEP8 代码规范常见问题及解决方案 Python3操作MySQL8.XX创建表|CRUD基本操作 Python3操作SQLite3创建表主键自增长|CRUD基本操作 anaconda3最新版安装|使用详情|Error: Please select a valid Python interpreter Python函数绘…

Python学习之九九乘法表

实例要求&#xff1a;每0.2秒出现一个算数表达式&#xff1b;下三角排列&#xff0c;呈现梯形状&#xff1b;实例分析&#xff1a;导入time包;使用双层while循环嵌套即可&#xff1b;示例代码&#xff1a; import timei 1 while i < 9:j 1while j < i:print("%-2…

Docker版部署RocketMQ开启ACL验证

一、拉取镜像 docker pull apache/rocketmq:latest 二、准备挂载目录 mkdir /usr/local/rocketmq/data mkdir /usr/local/rocketmq/conf 三、运行 docker run \ -d \ -p 9876:9876 \ -v /usr/local/rocketmq/data/logs:/home/rocketmq/logs \ -v /usr/local/rocketmq/data…