使用生产者和消费者算法加速数据处理

应用场景

数据库里有1120万条数据需要一个不漏的全部处理,然后将处理后的数据再次保存在数据库中。如果数据量小的话,取出来后挨个处理挨个进行保存即可,此时我们面对的是千万级别的大批量的数据,挨个处理挨个保存这种顺序方法非常耗时,不可行。
在这里插入图片描述

方法使用

此时可以选择一个生产者和消费者思路进行处理,如下图顺序方法和生产者消费者方法的对比。
顺序执行的耗时模型处理数据处理数据完成后才可以执行保存数据,耗时是叠加;生产消费方法执行耗时是生产数据消费数据方法并行的执行状态,消耗时间取决于哪个最后执行完成(此图中生产数据执行时间最长)。
在这里插入图片描述

首先创建线程安全的队列,用于生产者和消费者的数据传递。生产者在处理完成一条数据后,把数据放入队列中,消费者不断的检查队列中是否存在数据,如果存在数据就进行取出处理后保存。

private Queue<RelateCountMatrixEntity> queue = new ConcurrentLinkedQueue<>();

这种方式解放生产者 存储数据库这种耗时的瓶颈,把精力放在处理数据的身上;消费者没有了处理数据中繁琐的计算瓶颈,把精力全部放在存储数据上。

生产者代码

public void produce() {
   //为消费者开启一个线程单独运行
   new Thread(this::consumerQueue).start();
   long startTime = System.currentTimeMillis();

   //处理数据
   Data data = null;
   while ((data = getData()) != null) {
   	   //处理data数据并将data添加到队列中
   	   queue.offer(data);
       lastId = userAndUserMatrix(lastId);
   }
   //存放到队列中最后一条数据,最后一条记录设置为-1,便于消费者处理
   queue.offer(-1);

   long wasteTime = System.currentTimeMillis() - startTime;
   logger.info("消耗时间:{}", wasteTime);
}

在生产者方法中开启了一个线程运行消费者方法,消费者实时观察队列中是否有存在数据,不存在进行等待一秒避免无意义的CPU空转。消费者会实时判断是否最后一条记录,最后一条记录即退出这个死循环,运行该方法的线程会自动结束。
注意:在写到有死循环的代码时候,要确保有停住这个死循环的机制,不能让它一直无限制的空转.

//消费队列数据
private void consumerQueue() {
  while (true) {
      Data data = queue.poll();
      if (data == null) {
          try {
              logger.info("队列数据为空,等待1000ms...");
              Thread.sleep(1000);
          } catch (Exception e) {
              //
          }
      }
      //判断队列中是否是最后一条记录
      if (data != null && data == -1) {
          break;
      }
      if (data != null) {
          dao.saveRelateCount(data);
      }
  }
}

关于从库中获取全部记录,在之前的博客中有写到,谢谢查看 使用mongoTemplate id增量快速遍历整张表的所有数据

水平原因可能存在诸多问题,希望指出,谢谢

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值