前端实现【 批量任务调度管理器 】demo优化

news2024/9/9 0:46:01

一、前提介绍

我在前文实现过一个【批量任务调度管理器】的 demo,能实现简单的任务批量并发分组,过滤等操作。但是还有很多优化空间,所以查找一些优化的库,
主要想优化两个方面, 上篇提到的:

针对 3,其实可以自己手写一个,也可以依靠 如什么来实现。
针对 2,最难的是根据【当前系统负载或网络状况调整并发请求数量】,这必须需要引入一个检测系统的东西。

而动态调整数量,我现在的代码其实已经可以满足,我只是无法【获取当前系统负载或网络状况】。
当然我搜了一些,也有推荐 P-Queue 这类队列库来现在我现在的功能的,它有一些优点,比如:动态调整并发数、任务优先级、延迟、减少手动实现的复杂性,简化代码逻辑,提高可读性和维护性等等。

最后实现功能:基于 P-Queue 和 AbortController 的批量操作功能,其中包括了动态并发控制、网络状态监测和请求取消功能。

二、P-Queue 介绍

P-Queue 是一个基于 Promise 的优先队列,它允许你控制并发任务的数量,并且可以设置任务的优先级。P-Queue 的使用非常简单,只需要创建一个队列实例,然后使用 add 方法添加任务即可。

优点:

1. 固定并发数: 创建 P-Queue 实例时指定一个并发数,例如 5。这表示队列最多同时处理 5 个任务。
2. 自动调度:只需要将任务添加到队列中,而不需要关心任务的调度和执行顺序。P-Queue 会根据你指定的并发数自动处理任务——我现在自己手写的那个只是考虑使用 for 循环启动多个并发请求,并通过递归调用来处理下一任务。这种方法不涉及任务队列的概念,而是直接处理任务并发
3. 任务执行:任务被添加到队列时,P-Queue 会立即检查当前的并发任务数量。如果当前执行的任务数少于并发数限制,它会立即开始执行新的任务。
如果当前正在执行的任务数达到并发限制,P-Queue 会将新任务放入队列中,等待直到有空闲的并发槽位(即当前正在运行的任务数减少到低于并发限制)。
4. 任务完成:当一个任务完成时,P-Queue 会检查队列中的其他待处理任务。如果有任务在队列中等待并且当前并发数仍然未达到限制,它会自动开始执行下一个任务。

使用案例:

import PQueue from 'p-queue'
import axios from 'axios'

// 创建一个队列,设置并发数为 5
const queue = new PQueue({ concurrency: 5 })

const tasks = [
  () => axios.get('/api/task1'),
  () => axios.get('/api/task2')
  // 更多任务...
]

// 添加任务到队列中
tasks.forEach((task) => {
  queue.add(task)
})

// 动态调整并发数——可以根据系统的情况来调整
setTimeout(() => {
  queue.concurrency = 10 // 动态调整并发数
}, 5000)

// 等待所有任务完成
queue.onIdle().then(() => {
  console.log('All tasks completed')
})

三、动态检测的实现

我曾想过使用一些第三方库来实现检测当前系统的情况,然后动态控制并发数量,这样会更友好,查了一些方案,感觉没有必要。

实际的负载检测逻辑通常依赖于系统性能指标和资源使用情况。一些常见的负载检测方法和第三方库:

  1. os-utils:提供系统负载和资源使用情况的简单接口。
  2. systeminformation:提供详细的系统信息,包括 CPU、内存、网络等。
  3. node-os-utils:获取系统的 CPU、内存、磁盘和网络信息,适合用于 Node.js 环境。

对于大多数应用,特别是当任务负载和并发需求相对稳定时,动态调整可能显得过于复杂。遂放弃。

四、优化效果

最后,我的方案如下:
基于 P-Queue 和 AbortController 的批量操作功能,其中包括了动态并发控制、网络状态监测和请求取消功能。以下是实现功能的详细描述:

功能优化概述

  1. 动态并发控制:getConcurrency:根据设备的硬件线程数(CPU 核心数)动态计算并发请求数量,一个比较基础的检测,也可以考虑其他的检查
  2. 队列 queue:使用 P-Queue 创建任务队列,初始化并发数量。
  3. 监听网络是否中断,再批量请求处理:每个请求的处理函数,使用 AbortController 允许在网络断开时中断请求。
  4. 注意:组件挂载时初始化网络状态监听、也可以考虑监听网络的情况更新 P-Queue 的并发数量

优点是:可扩展性强,还是比较简单灵活,结合了并发控制、请求取消和网络状态检测。能够提升性能,优化用户体验。

代码实现

import PQueue from 'p-queue'
import axios from 'axios'

onMounted(() => {
  window.addEventListener('online', handleNetworkChange)
  window.addEventListener('offline', handleNetworkChange)
})
// 创建 AbortController 实例
let abortController = new AbortController()

// 网络状态检测函数
const isOnline = () => navigator.onLine
// 定义动态并发控制函数(根据需要自定义)
const getConcurrency = () => {
  //目的是根据系统的硬件资源或其他条件动态调整并发请求的数量。具体来说,它通过 navigator.hardwareConcurrency 获取设备的硬件线程数(CPU核心数),然后将其限制在一个合适的范围内(在这个例子中是 1 到 10)
  // 你可以根据系统负载、网络状况等动态调整并发数
  return Math.max(1, Math.min(10, navigator.hardwareConcurrency || 4))
}

// 创建 P-Queue 实例
const queue = new PQueue({ concurrency: getConcurrency() })

// 更新并发数的函数
const updateConcurrency = () => {
  queue.concurrency = getConcurrency()
}
// 存储每个请求的 AbortController 实例
const controllers = ref([])
const batchOperation = (title, operationType, axiosConfig, shouldFilterList) => {
  const successCount = ref(0)
  const errorCount = ref(0)
  // 执行批量操作
  startLoading()

  const requestTaskList = shouldFilterList
    ? tableData.value.filter((item, index, arr) => arr.findIndex((val) => val.id === item.id) === index)
    : tableData.value

  if (requestTaskList.length === 0) {
    ElMessage.error('没有可操作的任务!')
    stopLoading()
    return
  }

  // 定义请求函数
  const requestFunction = async (row) => {
    // 创建新的 AbortController 实例
    const controller = new AbortController()
    controllers.value.push(controller) // 将控制器添加到集合中
    const params = {}

    try {
      const res = await axios.request({
        url: axiosConfig.url,
        method: axiosConfig.method,
        params: params,
        signal: abortController.signal // 使用 AbortController 实例
      })

      if (res.data.code === 200) {
        successCount.value++
      } else {
        errorCount.value++
      }
    } catch (error) {
      if (error.name === 'AbortError') {
        console.warn('Request was aborted due to network being offline.')
      } else {
        errorCount.value++
        console.error('Request failed:', error)
      }
    }
  }

  requestTaskList.forEach((row) => {
    queue.add(() => requestFunction(row))
  })

  queue.onIdle().then(() => {
    stopLoading(tabs)
    ElNotification({
      title: `${title}结果`,
      message: `${requestTaskList.length} 个任务,${successCount.value} 个处理成功,${errorCount.value} 个处理失败。`,
      type: errorCount.value === 0 ? 'success' : 'warning'
    })
    controllers.value = [] // 清空控制器集合
  })

  // 动态调整并发数的定时器(每隔 5 分钟更新一次)——感觉作用不大,会导致不必要的性能开销
  // setInterval(() => {
  //   queue.concurrency = getConcurrency()
  // }, 300000)
}
// 取消所有请求
const cancelAllRequests = () => {
  controllers.value.forEach((controller) => {
    controller.abort()
  })
  controllers.value = [] // 清空控制器集合
}
// 监听网络状态变化
const handleNetworkChange = () => {
  if (!isOnline()) {
    console.log('Network is offline. Cancelling ongoing requests.')
    cancelAllRequests() // 取消所有请求
  } else {
    console.log('Network is back online. Resuming requests.')
    abortController = new AbortController() // 创建新的 AbortController 实例
  }
}

// 在组件卸载之前,取消所有未完成的请求
onBeforeUnmount(() => {
  isUnmount.value = true
  window.removeEventListener('online', handleNetworkChange)
  window.removeEventListener('offline', handleNetworkChange)
  cancelAllRequests() // 组件卸载时取消所有请求
})

效果评价

1.并发数测试
同样 20 条,优化前:
在这里插入图片描述

优化第一版,上篇:
在这里插入图片描述

优化第二版,这版:
在这里插入图片描述

其实吧,我也看不出来,性能有啥变化,累了,还是太少了吧……
但是,代码友好了一些些吧,并发上来讲,比之前好很多。

2.取消请求测试
同样 20 条,优化前,没有加取消的功能,断网会——500!如果你的 axios 拦截里对 500 进行处理的话,就会误伤。

优化后:
会取消。

五、总结

待完善~

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

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

相关文章

“数说”巴黎奥运会上的“中国智造”成果

引言:随着“中国智造”在欧洲杯上方兴未艾,在巴黎奥运会上,中国智造继续以多种形式和领域展现了其强大的实力和创新能力。以格力公开表示将为巴黎奥运村提供345台格力空调,为中国制造的清凉送至巴黎事件拉开中国制造闪亮巴黎奥运会…

CTF Web SQL注入 10000字详解

这里写目录标题 涉及的数据库知识unionorder bydatabase()information_schemalimit--空格注释replaceinto outfilelikeGROUP BYHAVINGGROUP BY、HAVING、WHERE之间的关系regexp 原理信息收集操作系统数据库判断注入点注入点类型POST注入数字型注入字符型注入搜索型注入Insert/u…

Debian12 安装Docker 用 Docker Compose 部署WordPress

服务器准备: 以root账号登录,如果不是root,后面指令需要加sudo apt update apt install apt-transport-https ca-certificates curl gnupg lsb-release添加GPG密钥,推荐国内源 curl -fsSL https://mirrors.aliyun.com/docker…

ArchLinux部署waydroid

在Arch Linux系统上部署Waydroid运行Android APP 文章目录 在Arch Linux系统上部署Waydroid运行Android APP1. 安装要求2. 本机环境3. 安装 Waydroid4. 网络配置5.注册Google设备6. 运行效果图 Waydroid是Anbox配合Haliun技术开发的LXC Android容器,可在GUN/Linux系…

C语言中的指针基础

文章目录 🍊自我介绍🍊地址🍊C语言中的指针 你的点赞评论就是对博主最大的鼓励 当然喜欢的小伙伴可以:点赞关注评论收藏(一键四连)哦~ 🍊自我介绍 Hello,大家好,我是小珑也要变强&am…

Spring Boot 3 + Resilience4j 简单入门 + Redis Cache 整合

1. 项目结构 2. Maven依赖 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.1.2</version><relativePath/> <!-- lookup parent from repository --&…

CSRF Token 原理

CSRF 攻击 CSRF 攻击成功的关键是&#xff0c;恶意网站让浏览器自动发起一个请求&#xff0c;这个请求会自动携带 cookie &#xff0c;正常网站拿到 cookie 后会认为这是正常用户&#xff0c;就允许请求。 防范 如果在请求中加一个字段&#xff08;CSRF Token&#xff09;&am…

C++笔记之指针基础

函数重载:(C++特性) 定义: C++允许函数重名,但是参数列表要有区分 在相同的作用域定义同名的函数,但是它们的参数要有所区分,这样的多个函数构成重载关系 objdump -d test.exe >log.txt 将test.exe反汇编并将结果重定向到log.txt 文件中 ,然后在 log.txt中找到定…

学习网络安全 为什么Linux首择Kali Linux? 以及如何正确的使用Kali Linux

1.什么是kali linux&#xff1f; Kali Linux是一款基于Debian的Linux发行版&#xff0c;主要用于网络安全测试和渗透测试。它由全球顶尖的安全专家和黑客社区维护开发&#xff0c;提供了丰富的工具和资源&#xff0c;用于测试安全性、漏洞利用和渗透测试。此外&#xff0c;Kal…

MySQL 性能调优

文章目录 一. MySQL调优金字塔1. 架构调优2. MySQL调优3. 硬件和OS调优4. 小结 二. 查询性能调优三. 慢查询1. 概念2. 优化数据访问3. 请求了不需要数据&#xff0c;怎么做4. 是否在扫描额外的记录5. 慢查询相关配置 & 日志位置6. 小结 四. 查询优化器五. 实现调优手段 一.…

24、Python之面向对象:责任与自由,私有属性真的有必要吗

引言 前面我们进一步介绍了类定义中属性的使用&#xff0c;今天我们对中关于属性私有化的话题稍微展开聊一下&#xff0c;顺便稍微理解一下Python设计的相关理念。 访问级别 在其他编程语言中&#xff0c;比如Java&#xff0c;关于类中的属性和方法通过关键字定义明确的访问级…

1、仓颉工程基础操作 cjpm

文章目录 1. 仓颉工程创建方式2. cjpm2.1 init 初始化工程2.2 run 运行工程 1. 仓颉工程创建方式 使用 cangjie studio 通过cangjie studio 创建 使用vscode插件 通过 VSCode 命令面板创建仓颉工程通过可视化界面创建仓颉工程 cjpm 注&#xff1a;具体使用参考官方文档&#…

探索分布式光伏运维系统的组成 需要几步呢?

前言 随着光伏发电的不断发展&#xff0c;对于光伏发电监控系统的需求也日益迫切&#xff0c;“互联网”时代&#xff0c;“互联网”的理念已经转化为科技生产的动力&#xff0c;促进了产业的升级发展&#xff0c;本文结合“互联网”技术提出了一种针对分散光伏发电站运行数据…

浅谈Devops

1.什么是Devops DevopsDev&#xff08;Development&#xff09;Ops&#xff08;Operation&#xff09; DevOps&#xff08;Development和Operations的混合词&#xff09;是一种重视“软件开发人员&#xff08;Dev&#xff09;”和“IT运维技术人员&#xff08;Ops&#xff09;”…

asp.net mvc 三层架构开发商城系统需要前台页面代完善

一般会后端开发&#xff0c;都不太想写前台界面&#xff0c;这套系统做完本来想开源&#xff0c;需要前台界面&#xff0c;后台已开发&#xff0c;有需求的朋友&#xff0c;可以开发个前端界面完善一下&#xff0c;有的话可以私聊发给我啊

The Llama 3 Herd of Models 第6部分推理部分全文

第1,2,3部分 介绍,概览和预训练 第4部分 后训练 第5部分 结果 6 Inference 推理 我们研究了两种主要技术来提高Llama 3405b模型的推理效率:(1)管道并行化和(2)FP8量化。我们已经公开发布了FP8量化的实现。 6.1 Pipeline Parallelism 管道并行 当使用BF16数字表示模型参数时…

VirtualBox创建共享磁盘

VirtualBox创建共享磁盘 目录 VirtualBox创建共享磁盘1、划分共享磁盘1.1、【管理】->【工具】->【虚拟介质管理】1.2、【创建】->【VDI&#xff08;VirtualBox 磁盘映像&#xff09;】->【下一步】1.3、【预先分配全部空间】->【下一步】1.4、【分配大小】->…

5、springboot3 vue3开发平台-后端- satoken 整合

文章目录 1. 为什么使用sa-token2. 依赖导入jichu2.1 基础依赖引入2.2 redis整合2.3 redis 配置&#xff0c; 使redis能支持中文存储 3. 配置4. 配置使用4.1 权限加载接口实现&#xff0c; 登录实现4.2 配置全局过滤器4.3 登录异常处理 5. 登录测试6. 用户session的获取 1. 为什…

MySQL索引与存储引擎、事物

数据库索引 是一个排序的列表&#xff0c;存储着索引值和这个值所对应的物理地址 无须对整个表进行扫描&#xff0c;通过物理地址就可以找到所需数据 是表中一列或者若干列值排序的方法 需要额外的磁盘空间 类型 普通索引 最基本的索引类型&#xff0c;没有唯一性之类的限制 创…

图不连通怎么办?

目录 1.问题 2.连通的相关概念 3.解决方案 C语言示例实现&#xff1a; 1.问题 无论是图的深度还是广度遍历都是从图的某一条边往下走&#xff0c;那么被孤立的结点怎么被遍历到呢&#xff1f; 2.连通的相关概念 连通&#xff1a;如果从V到W存在一条&#xff08;无向&#…