博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
一种Furture模式处理请求中循环独立的任务的方法
阅读量:4082 次
发布时间:2019-05-25

本文共 3299 字,大约阅读时间需要 10 分钟。

业务中经常碰到查询一个list后又需要对list进行后续处理(在sql层面不方便处理),需要循环遍历list

如果list中各item的业务独立,可用future模式来大大提高性能

1.关于future模式的概念

参考:彻底理解Java的Future模式  https://www.cnblogs.com/cz123/p/7693064.html

先上一个场景:假如你突然想做饭,但是没有厨具,也没有食材。网上购买厨具比较方便,食材去超市买更放心。

实现分析:在快递员送厨具的期间,我们肯定不会闲着,可以去超市买食材。所以,在主线程里面另起一个子线程去网购厨具。

但是,子线程执行的结果是要返回厨具的,而run方法是没有返回值的。所以,这才是难点,需要好好考虑一下。

2.关于实现

(1) callable+future+线程池:

  1. Future<Integer> future =es.submit(calTask);  
callable无法直接start,需要借助线程池

Future<T> = 线程池.submit(Callable<T>);

Future<T>.get();

(2)   callable +futuretask+线程池

  1. FutureTask<Integer> futureTask=new FutureTask<>(calTask);  
  2.         //执行任务  
  3.         es.submit(futureTask);  
FutureTask<T> = new FutureTask<T>(Callable<T>);

线程池.submit(FutureTask<T>)

FutureTask<T>.get();

(3)   callable +futuretask+Thread

同时FureTask也实现了runnable,可以直接允许不用线程池

FutureTask
ft = new FutureTask
((Callable
) Thread thread = new Thread(ft);thread.start;
FutureTask<T> = new FutureTask<T>(Callable<T>);

Thread = new Thread(FutureTask<T>);

Thread.start();

FutureTask<T>.get();

参考:Java多线程编程:Callable、Future和FutureTask浅析(多线程编程之四)     博客比较深入

http://blog.csdn.net/javazejian/article/details/50896505  

3. 应用

业务模型是这样的:

List
= sql;for(T : list
) { sql(T); T.doSomething();}

以future模式重构

List
= sql;List
> taskList = new ArrayList
>(list.size());for(T t: list
) { FutureTask
f = new FutureTask
(new TaskCallable
(t)); taskList.add(f); Thread thread = new Thread(f); thread.start();}for(FutureTask
ft : taskList) { ft.get();}
将T分为多个线程并行处理,同时等待所有计算结果,整合后返回

这种模式在业务中达到以下效果:

原(ms) 现(ms)
455 179
422 152
422 120
450 102
517 92
480 88
   

另一个请求:

原 A(ms) 现 B(ms)
1217 216
584 184
505 171
503 116
556 96
线上60ms 22ms
   

可以看到,微观上响应速度提高了5倍

以腾讯压力测试:

  A B
20并发(4*4)2分钟 第一次 tps:127.18   97.15ms tps:212.98    57.57ms
第二次 tps:123.59  100.57ms tps:208.77   57.50ms
100并发  唯一一次 tps:241.39  233.02ms tps:256.48   209.21ms
不处理   唯一一次     tps:793.77  71.93ms    
     
     
分析:

20并发下,性能差不多差一倍

100并发下,差距不大了,推测为mysql顶不住了,证明这种方案在高压下不可取,原本一次查询变成了n+1次,应尽量避免

4.封装

虽然原则上予以避免,力求在单次sql层面解决,但迫于需求频繁修改,由于这种情况比较常见,故封装一下:

@Servicepublic class FurtureService
{ /** * * @param o 外部类对象,用于取得某对象的内部类 * @param list 待循环多线程处理的数据 * @param c 内部Callable类型 * @param args 内部类参数 数组 */ public void run(Object o, List
list, Class c, Object [] args) throws IllegalAccessException, InvocationTargetException, InstantiationException, ExecutionException, InterruptedException { List
> taskList = new ArrayList
>(list.size()); // ExecutorService exec = Executors.newFixedThreadPool(list.size()); Constructor [] constructor = null; constructor = c.getConstructors(); for(int i=0; i
ft = new FutureTask
((Callable
) constructor[0].newInstance(o, list.get(i), args)); taskList.add(ft); // exec.submit(ft); Thread thread = new Thread(ft); thread.start(); } for (FutureTask
ft : taskList) { ft.get(); } // exec.shutdown(); }}
调用:

@Autowired    private FurtureService
furtureService;
furtureService.run(this, list, ComputeTask.class, new Object[]{para});

其实还是有优点的:

1.提高了cpu使用率

2.一定程度弥补了不能在数据库层面一并取出数据的性能

缺点:

1.数据库压力倍增,1次sql变成了n+1次sql查询

 

355

308

311

275

271

205

178

119

105

84

91

96

455

422

422

450

517

480

250

179

152

120

102

92

88

你可能感兴趣的文章
这些网站有一些嵌入式面试题合集
查看>>
我觉得刷题是有必要的,不然小心实际被问的时候懵逼,我觉得你需要刷个50份面试题。跟考研数学疯狂刷卷子一样!
查看>>
我觉得嵌入式面试三要素:基础吃透+项目+大量刷题,缺一不可。不刷题是不行的。而且得是大量刷,刷出感觉套路,别人做题都做得是固定题型套路条件反射了,你还在那慢慢理解慢慢推是不行的,也是考研的教训。
查看>>
相机标定的目的:获取摄像机的内参和外参矩阵(同时也会得到每一幅标定图像的选择和平移矩阵),内参和外参系数可以对之后相机拍摄的图像就进行矫正,得到畸变相对很小的图像。
查看>>
现在来看,做个普罗米修斯的docker镜像对我而言并不难,对PX4仿真环境配置也熟悉了。
查看>>
删除docker容器和镜像的命令
查看>>
VINS-Fusion Intel® RealSense™ Depth Camera D435i
查看>>
使用Realsense D435i运行VINS-Fusion并建图
查看>>
matlab函数im2bw_图像分割之阈值分割(matlab)(转载)
查看>>
gazebo似乎就是在装ROS的时候一起装了,装ROS的时候选择的是ros-melodic-desktop-full的话。
查看>>
在React项目中优雅地使用Typescript
查看>>
React + TypeScript 默认 Props 的处理
查看>>
React + TypeScript 实现泛型组件
查看>>
TypeScript 完全手册
查看>>
从React-Native坑中爬出,我记下了这些
查看>>
React Native之原理浅析
查看>>
Git操作清单
查看>>
手把手入门Fish-Redux开发flutter(上)
查看>>
从React16生命周期到React fiber架构
查看>>
基础算法
查看>>