多条任务排队设计思想

多条任务设计思想

需求:

最近工作中需要做一个类似百度网盘中的下载列表。在列表中实现任务置顶,任务上下,移动,删除等操作。
发送任务,任务进入到等待队列中,按照传入的顺序执行打包任务。打包任务能够实现,置顶,上下移动等操作。

请添加图片描述

我尝试了多种方案,包括Deque 双向队列、Redis列表中查询数据、Mysql实现思路。

1 Deque双向队列例子

Deque 双向队列 API

import java.util.Deque;
import java.util.ArrayDeque;
 
public class DequeExample {
    public static void main(String[] args) {
        // 创建一个Deque对象
        Deque<String> deque = new ArrayDeque<>();
 
        // 添加元素到双端队列
        deque.addFirst("Apple");
        deque.addLast("Banana");
        deque.addLast("Orange");
 
        // 获取双端队列头部和尾部元素
        String first = deque.getFirst();
        String last = deque.getLast();
        System.out.println("头部元素:" + first);
        System.out.println("尾部元素:" + last);
 
        // 遍历双端队列并输出元素
        System.out.println("双端队列元素(从头到尾):");
        for (String element : deque) {
            System.out.println(element);
        }
 
        // 移除双端队列头部和尾部元素
        String removedFirst = deque.removeFirst();
        String removedLast = deque.removeLast();
        System.out.println("移除的头部元素:" + removedFirst);
        System.out.println("移除的尾部元素:" + removedLast);
 
        // 双端队列大小
        int size = deque.size();
        System.out.println("双端队列大小:" + size);
 
        // 判断双端队列是否为空
        boolean isEmpty = deque.isEmpty();
        System.out.println("双端队列是否为空:" + isEmpty);
    }
}

最先想到的就是双向队列(先进先出),任务添加到队列后,放在任务尾部。

img

服务内部,设置了两个存储,分别是等待队列以及数据库。

数据库中只显示

  • 打包完成 Done 、 打包失败 Failed、正在运行 Running

等待队列存放

  • 等待队列 Queued

当我拿到所有的打包任务时,会把数据库中的队列、等待队列进行拼接展示。

该方法在只有一台服务器上是没有问题的,但是服务会部署到多台服务器上,在分布式项目系统中会做负载均衡,避免由于一台服务出现故障服务造成不可用的情况,所以同一个服务会部署到多台服务器上。当任务发送打包任务时,任务会分发到不同的服务上。

假设有服务器A和B,有6条打包任务(任务编号为1,2,3,4,5,6)。此时服务器A机器接收 1, 3 , 4打包任务,在服务B接受2,5,6任务。任务列表展示会出现闪烁现象。(原因当客户端,获取列表时,从A、B中获取列表不断轮询)所以列表会在(1,3,4 )、(2,5,6)闪烁。另外列表中会出现Running的任务会消失一会儿再出现,由于任务打包后,任务进入修改其状态时,需要消耗一些时间。

2 Redis list队列

为了解决上述中列表闪烁问题。主要原因是,两个服务之间没有进行数据共享,所以我采用了redis,对数据进行共享。设计思路与上述一样,先进先出

redisTemplate ListRedis详解Redis 操作

@RequestMapping(value = "/list")
@ResponseBody
public String listTest(HttpServletRequest request) {

    // 向列表中头部添加元素
    redisTemplate.opsForList().leftPush("list", "第一个list元素");
    // 通过index获取列表中的元素
    System.out.println(redisTemplate.opsForList().index("list", 0));

    // 把多个值存入列表头部
    redisTemplate.opsForList().leftPushAll("list", "第二个list元素", "第三个list元素", "第四个list元素");

    // 获取列表指定范围内元素,start起始位置,end结束位置,-1返回所有
    System.out.println(redisTemplate.opsForList().range("list", 0, 3));

    // list存在的时候再加入
    redisTemplate.opsForList().leftPushIfPresent("list", "第六个list元素");
    System.out.println(redisTemplate.opsForList().range("list", 0, -1));

    // 在pivot值存在时在pivot前面添加
    redisTemplate.opsForList().leftPush("list", "第六个list元素", "第五个半list元素");
    System.out.println(redisTemplate.opsForList().range("list", 0, -1));

    // 按照先进先出的原则添加多个值
    redisTemplate.opsForList().rightPush("list", "第七个list元素");
    redisTemplate.opsForList().rightPushAll("list", "第八个list元素", "第九个list元素");
    System.out.println(redisTemplate.opsForList().range("list", 0, -1));

    // 在pivot右边添加值
    redisTemplate.opsForList().rightPush("list", "第七个list元素", "第七个半list元素");
    System.out.println(redisTemplate.opsForList().range("list", 0, -1));

    // 设置指定索引处元素的值
    redisTemplate.opsForList().set("list", 5, "修改后的list元素");

    // 移除并获取列表中第一个元素
    System.out.println(redisTemplate.opsForList().leftPop("list"));
    System.out.println(redisTemplate.opsForList().leftPop("list", 10, TimeUnit.SECONDS));

    // 移除并获取列表中最后一个元素
    System.out.println(redisTemplate.opsForList().rightPop("list"));
    System.out.println(redisTemplate.opsForList().rightPop("list", 8, TimeUnit.SECONDS));

    // 从一个列表右边弹出一个元素并将该元素插入另一个列表的左边
    redisTemplate.opsForList().rightPopAndLeftPush("list", "list2");
    redisTemplate.opsForList().rightPopAndLeftPush("list", "list2", 10, TimeUnit.SECONDS);

    // 删除列表中值等于指定value的元素,index=0删除所有,index>0删除头部开始第一个,index<0删除尾部开始第一个
    redisTemplate.opsForList().remove("list", 0, "第三个list元素");
    System.out.println(redisTemplate.opsForList().range("list", 0, -1));

    // 列表进行裁剪
    redisTemplate.opsForList().trim("list", 1, 4);
    System.out.println(redisTemplate.opsForList().range("list", 0, -1));

    // 获取当前列表长度
    System.out.println(redisTemplate.opsForList().size("list"));

    return null;
}

但是该方法,仍然会出现正在运行的列表会消失。主要原因,发送打包任务该过程是一个很消耗时间的过程,任务状态的修改不及时,在等待队列任务弹出后(队列中就不存在该任务),可是数据库的任务状态仍然是Queued(不显示Queued)。只有当打包发送成功,任务有返回的数据,才能够及时修改任务状态,任务才展示到列表中**(添加线程,也可以解决上述问题)**。

3 Mysql数据库优化

上述问题中,Running消失,主要原因是打包任务耗时,照成Queued 状态不能及时被修改。

为了解决上述问题,我在数据库中添加了一个index 字段。

3.1 流程

index = 1 列表大小取决于,打包服务器的数量。假如有3台打包服务器,index = 1 列表就会有3个。最少为3个

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.2 设计目的:

如果没每一个数据设置编号(1,2,3,4,5,6,7)

假如 7 号任务置顶时,在数据库中就要修改7 条数据,需要将7 之前数据需要修改,会对数据库照成很大的压力。
该方法中,假设有2台打包服务器,有7条打包任务,将编号7 置顶,只需要将 7,7 的编号修改为 index = 1即可。

操作将7号置顶
实际顺序(1, 2, 3, 4, 5, 6, 7)(7, 1, 2, 3, 4, 5, 6)
indexs(1,1, 2, 2, 2, 2, 2 )(1, 1, 1, 2, 2, 2, 2)

置顶,新创建一个更新时间,上下移动交换任务的更新时间。

index = 1 是按照更新时间从大到小排序

index = 2 按照更新时间的从小到大排序

order by indexs,
    case when indexs = 1 then update_time end asc,
    case when indexs = 2 then update_time end asc,
    case when indexs = 3 then update_time end desc
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
AI多任务排队调用GPU任务队列是一种通过合理管理和调度GPU资源来实现多任务并行处理的方法。在AI应用中,由于任务复杂度高、计算需求大,常常需要借助GPU来加速计算。而多任务处理则能提高效率,使得多个任务可以同时进行,而不是一个一个顺序执行。 在实现多任务排队调用GPU任务队列的过程中,首先需要建立一个任务队列。队列中存储了待执行的任务,并按照先进先出的原则进行调度。当一个任务需要借助GPU来进行运算时,它会被加入到GPU任务队列中,并等待GPU资源的分配。 对GPU资源的分配可以根据任务的优先级进行调度。在任务队列中,每个任务都有一个相应的优先级,优先级高的任务会被优先分配GPU资源。这样可以确保关键任务能够及时得到GPU的资源支持。 当GPU资源有空余时,调度程序会从任务队列中选取一个优先级最高的任务,将其分配给GPU进行处理。而其他任务则会继续等待,直到GPU资源变得可用。 通过多任务排队调用GPU任务队列,可以实现多个任务的并行处理,充分利用GPU资源,提高计算效率。同时,队列的使用可以有效控制任务的执行顺序,避免资源浪费和冲突。 综上所述,AI多任务排队调用GPU任务队列是一种高效、合理地管理GPU资源,提高多任务并行处理效率的方法。它能够满足AI应用中对计算资源的需求,同时保证任务的执行顺序和优先级,进一步优化计算性能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值