首页 > 其他分享 >CompletableFuture 异步编排

CompletableFuture 异步编排

时间:2023-08-13 16:47:08浏览次数:35  
标签:sku 异步 skuId skuItemVo 获取 编排 info CompletableFuture

 

 1. 业务场景

   查询商品详情页的逻辑比较复杂,有些数据还需要远程调用,必然需要花费更多的时间。

  假如商品详情页的每个查询,需要如下标注的时间才能完成,那么,用户需要 5.5s 后才能看到商品详情页的内容。很显然是不能接受的,如果有多个线程同时完成这 6 步操作,也许只需要 1.5s 即可完成响应。

  获取sku基本信息(0.5s);获取sku的图片信息(0.5s);获取sku的促销信息(1s);获取spu的所有销售属性(1s);获取规格参数组及规格参数(1.5s);spu详情(1s)

 

2. 查询商品详情接口实现

    @GetMapping("/{skuId}.html")
    public String skuItem(@PathVariable("skuId") Long skuId, Model model) throws ExecutionException, InterruptedException {

        System.out.println("准备查询" + skuId + "详情");
        long start = System.currentTimeMillis();

        SkuItemVo vos = skuInfoService.item(skuId);

        model.addAttribute("item",vos);

        long end = System.currentTimeMillis();
        System.out.println("改造前耗时:" + (end - start));

        return "item";
    }

    @Override
    public SkuItemVo item(Long skuId) throws ExecutionException, InterruptedException {
        SkuItemVo skuItemVo = new SkuItemVo();
        //1、sku基本信息的获取  pms_sku_info
        SkuInfoEntity info = getById(skuId);
        skuItemVo.setInfo(info);
        Long catalogId = info.getCatalogId();
        Long spuId = info.getSpuId();

        //2、sku的图片信息    pms_sku_images
        List<SkuImagesEntity> images = skuImagesService.getImagesBySkuId(skuId);
        skuItemVo.setImages(images);
        //3、获取spu的销售属性组合
        List<SkuItemSaleAttrVo> saleAttrVos = skuSaleAttrValueService.getSaleAttrBySpuId(spuId);
        skuItemVo.setSaleAttr(saleAttrVos);

        //4、获取spu的介绍    pms_spu_info_desc
        SpuInfoDescEntity spuInfoDescEntity = spuInfoDescService.getById(spuId);
        skuItemVo.setDesc(spuInfoDescEntity);
        //5、获取spu的规格参数信息
        List<SpuItemAttrGroupVo> attrGroupVos = attrGroupService.getAttrGroupWithAttrsBySpuId(spuId, catalogId);
        skuItemVo.setGroupAttrs(attrGroupVos);

        return skuItemVo;
    }

  在未使用异步编排之前所有的信息的查询都是串行获取的,执行后3000ms左右  

 

3.  CompletableFuture 异步编排

  在Java8中可以使用CompletableFuture 异步编排,sku的基本信息是先要获取的,当获取到基本信息后可以使用异步编排同时进行其他任务信息的获取,当所有任务都执行完成后,才返回实体;

  (1)在配置文件中声明线程池的配置信息

#application.properties
#配置线程池
gulimall.thread.coreSize=20
gulimall.thread.maxSize=200
gulimall.thread.keepAliveTime=10

  (2)创建线程池配置类,从配置文件中获取线程信息

@ConfigurationProperties(prefix = "gulimall.thread")
// @Component
@Data
public class ThreadPoolConfigProperties {

    private Integer coreSize;

    private Integer maxSize;

    private Integer keepAliveTime;


}

  (3)创建自定义线程池

@EnableConfigurationProperties(ThreadPoolConfigProperties.class)
@Configuration
public class MyThreadConfig {


    @Bean
    public ThreadPoolExecutor threadPoolExecutor(ThreadPoolConfigProperties pool) {
        return new ThreadPoolExecutor(
                pool.getCoreSize(),
                pool.getMaxSize(),
                pool.getKeepAliveTime(),
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(100000),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy()
        );
    }

}

  (4)对接口进行改造

    @GetMapping("/{skuId}.html")
    public String skuItem(@PathVariable("skuId") Long skuId, Model model) throws ExecutionException, InterruptedException {

        System.out.println("准备查询" + skuId + "详情");
        long start = System.currentTimeMillis();

        SkuItemVo vos = skuInfoService.item(skuId);

        model.addAttribute("item",vos);

        long end = System.currentTimeMillis();
        System.out.println("改造前耗时:" + (end - start));

        return "item";
    }

    @Override
    public SkuItemVo item(Long skuId) throws ExecutionException, InterruptedException {
        SkuItemVo skuItemVo = new SkuItemVo();

        //1、sku基本信息的获取  pms_sku_info
        CompletableFuture<SkuInfoEntity> infoFutrue = CompletableFuture.supplyAsync(() -> {
            SkuInfoEntity info = getById(skuId);
            skuItemVo.setInfo(info);
            return info;
        }, executor);

        //3、获取spu的销售属性组合
        CompletableFuture<Void> saleAttrFuture = infoFutrue.thenAcceptAsync((res)->{
            List<SkuItemSaleAttrVo> saleAttrVos = skuSaleAttrValueService.getSaleAttrBySpuId(res.getSpuId());
            skuItemVo.setSaleAttr(saleAttrVos);
        },executor);

        //4、获取spu的介绍    pms_spu_info_desc
        CompletableFuture<Void> descFuture = infoFutrue.thenAcceptAsync((res)->{
            SpuInfoDescEntity spuInfoDescEntity = spuInfoDescService.getById(res.getSpuId());
            skuItemVo.setDesc(spuInfoDescEntity);
        },executor);

        //5、获取spu的规格参数信息
        CompletableFuture<Void> baseAttrFuture = infoFutrue.thenAcceptAsync((res)->{
            List<SpuItemAttrGroupVo> attrGroupVos = attrGroupService.getAttrGroupWithAttrsBySpuId(res.getSpuId(), res.getCatalogId());
            skuItemVo.setGroupAttrs(attrGroupVos);
        },executor);

        //2、sku的图片信息    pms_sku_images
        CompletableFuture<Void> imageFuture = CompletableFuture.runAsync(() -> {
            List<SkuImagesEntity> images = skuImagesService.getImagesBySkuId(skuId);
            skuItemVo.setImages(images);
        }, executor);

        //等待所有任务都完成
        CompletableFuture.allOf(saleAttrFuture,descFuture,baseAttrFuture,imageFuture).get();
        return skuItemVo;
    }

  使用异步编排后,先获取到sku的基本信息,获取sku的图片信息可以与sku基本信息获取同时执行,剩下的任务等待任务1执行完成后都可以同时进行,等待所有的任务完成后才返回skuItemVo,消耗时间在900ms左右。

  总结:

  (1)CompletableFuture 中 runXxxx 都是没有返回结果的,supplyXxx 都是可以获取返回结果的,因为要获取到sku的基本信息的返回结果,所以使用supplyAsync,sku图片信息的获取不需要任务1的返回结果且可以与任务1同时执行;

  (2)可以使用自定义的线程池,否则就用默认的线程池;

  

标签:sku,异步,skuId,skuItemVo,获取,编排,info,CompletableFuture
From: https://www.cnblogs.com/homle/p/17626750.html

相关文章

  • 并发并行;同步异步;阻塞非阻塞
    并发/并行;同步/异步;阻塞/非阻塞并发/并行#并行同一时刻,执行多个任务的能力,并行必须是多cpu支持#并发同一时间段内,执行多个任务的能力,所有操作系统都支持并发,单核cpu也可以并发#串行多个任务依次进行,每个任务必须等待上一个任务完成才能开始#扯出去1.python开启多......
  • 异步线程变量传递必知必会---InheritableThreadLocal及底层原理分析
    InheritableThreadLocal简介笑傲菌:多线程热知识(一):ThreadLocal简介及底层原理3赞同·0评论文章上一篇文章我们聊到了ThreadLocal的作用机理,但是在文章的末尾,我提到了一个问题,ThreadLocal无法实现异步线程变量的传递。什么意思呢?以下面的代码为例子:@SneakyThrowspublicBo......
  • TaskDecorator——异步多线程中传递上下文等变量
    目录TaskDecorator定义TaskDecorator实例线程池使用TaskDecorator开发中很多数据如oauth2的认证信息,日志TracerId都是在请求线程中的,如果内部使用多线程处理就存在获取不到认证信息或TraceId的问题。这时候就需要处理子线程与主线程间数据传递的问题。TaskDecorator这个......
  • Docker容器编排
    docker-composecompose安装Compose简介Compose是用于定义和运行多容器Docker应用程序的工具。通过Compose,您可以使用YML文件来配置应用程序需要的所有服务。然后,使用一个命令,就可以从YML文件配置中创建并启动所有服务。Compose使用的三个步骤:使用Dockerfile定义......
  • CompletableFuture多任务组合回调
     1、AND组合关系thenCombine / thenAcceptBoth / runAfterBoth都表示:「当任务一和任务二都完成再执行任务三」。区别在于:「runAfterBoth」 不会把执行结果当做方法入参,且没有返回值「thenAcceptBoth」:会将两个任务的执行结果作为方法入参,传递到指定方法中,且无......
  • CompletableFuture异步多线程
    importjava.util.concurrent.CompletableFuture;importjava.util.concurrent.ExecutionException;publicstaticvoidmain(String[]args)throwsInterruptedException,ExecutionException{longstartTime=System.currentTimeMillis();//调用用户服......
  • CompletableFuture supplyAsync()
    CompletableFuture中的方法publicstaticCompletableFuture<Void>runAsync(Runnablerunnable)publicstaticCompletableFuture<Void>runAsync(Runnablerunnable,Executorexecutor)publicstatic<U>CompletableFuture<U>supplyAsync(Supplie......
  • 异步编程和多线程的关系
    引用自“https://zhuanlan.zhihu.com/p/570792890中bluecyan的留言”异步编程,它允许我们多个任务(Task)可以同时执行。多线程技术就是CPU利用多个线程来并发地运行多段逻辑。任务是逻辑层面的,线程是操作系统层面的,由线程ID标识,任务比线程抽象层级更高。异步任务可由线程实现,也可......
  • .NET Core多线程 (2) 异步 - 上
    去年换工作时系统复习了一下.NETCore多线程相关专题,学习了一线码农老哥的《.NET5多线程编程实战》课程,我将复习的知识进行了总结形成本专题。本篇,我们来复习一下异步的相关知识点,预计阅读时间10分钟。理解异步的本质(1)异步是什么?举个例子,在高峰期去餐厅吃饭,会先排队拿个小票,......
  • 最新版 redis-py 操作 redis(同步、异步、集群、连接池)
    现在的Python异步操作redis,有三种(aredis、aioredis、asynio_redis)但是都不推荐背景从redis.py4.2.0rc1+开始,Aioredis已经集成到redis-py中,并且Aioredis将不再更新维护,导入方式:fromredisimportasyncioasaioredis,本次验证的是redis==4.6.0#!/usr/bin/e......