美文网首页
接口异步调用,接口耗时减少的可不是一点点

接口异步调用,接口耗时减少的可不是一点点

作者: 红兔哥 | 来源:发表于2021-05-23 22:40 被阅读0次

随着业务发展,底层数据量越来越大,业务逻辑也日趋复杂化,某些接口耗时也越来越长,这时候接口就需要进行性能优化了,当然性能优化主要跟业务相关涉及改造点可能各不相同,这里就来介绍异步调用多个接口减少响应时间

适用条件

  • 调用多个独立的接口,接口间无相互依赖关系
  • 非耗时最大的接口占总耗时比重较大

优化前调用方式

优化前的代码按照顺序调用方式:

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class DemoTest {

    public static void main(String[] args) throws Exception {
        long beginTime = System.currentTimeMillis();
        int processA = new InterfaceA().process();
        int processB = new InterfaceB().process();
        int result = processA + processB;
        log.info("执行结果:{} 耗时:{}", result, System.currentTimeMillis() - beginTime);
    }

    @Slf4j
    public final static class InterfaceA {
        Integer result = 1;

        public int process() {
            long beginTime = System.currentTimeMillis();
            try {
                Thread.sleep(2000);
            } catch (Exception e) {
                log.error("InterfaceA.process Exception");
            }
            log.info("执行接口InterfaceA.process 耗时:{}ms", System.currentTimeMillis() - beginTime);
            return result;
        }
    }

    @Slf4j
    public final static class InterfaceB {
        Integer result = 1;

        public int process() {
            long beginTime = System.currentTimeMillis();
            try {
                Thread.sleep(2000);
            } catch (Exception e) {
                log.error("InterfaceB.process Exception");
            }
            log.info("执行接口InterfaceB.process 耗时:{}ms", System.currentTimeMillis() - beginTime);
            return result;
        }
    }
}

执行结果:

21:40:17.603 [main] INFO DemoTest$InterfaceA - 执行接口InterfaceA.process 耗时:2002ms
21:40:19.612 [main] INFO DemoTest$InterfaceB - 执行接口InterfaceB.process 耗时:2001ms
21:40:19.613 [main] INFO DemoTest - 执行结果:2 耗时:4018

优化后调用方式

优化后的代码按照异步调用方式:

import cn.hutool.core.thread.ThreadFactoryBuilder;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Slf4j
public class DemoTest {
    private static ThreadPoolExecutor pool = new ThreadPoolExecutor(
            5,
            5,
            60,
            TimeUnit.SECONDS,
            new ArrayBlockingQueue<Runnable>(1000),
            ThreadFactoryBuilder.create().setNamePrefix("线程名称-").build()
    );

    public static void main(String[] args) throws Exception {
        long beginTime = System.currentTimeMillis();

        List<Future<Integer>> futures = new ArrayList<>(2);
        List<Integer> results = new ArrayList<>(2);
        futures.add(pool.submit(() -> new InterfaceA().process()));
        futures.add(pool.submit(() -> new InterfaceB().process()));
        for (Future<Integer> item : futures) {
            results.add(item.get());
        }
        
        int result = results.get(0) + results.get(1);
        log.info("执行结果:{} 耗时:{}", result, System.currentTimeMillis() - beginTime);
    }

    @Slf4j
    public final static class InterfaceA {
        Integer result = 1;

        public int process() {
            long beginTime = System.currentTimeMillis();
            try {
                Thread.sleep(2000);
            } catch (Exception e) {
                log.error("InterfaceA.process Exception");
            }
            log.info("执行接口InterfaceA.process 耗时:{}ms", System.currentTimeMillis() - beginTime);
            return result;
        }
    }

    @Slf4j
    public final static class InterfaceB {
        Integer result = 1;

        public int process() {
            long beginTime = System.currentTimeMillis();
            try {
                Thread.sleep(2000);
            } catch (Exception e) {
                log.error("InterfaceB.process Exception");
            }
            log.info("执行接口InterfaceB.process 耗时:{}ms", System.currentTimeMillis() - beginTime);
            return result;
        }
    }
}

执行结果:

22:03:43.180 [线程名称-1] INFO DemoTest$InterfaceB - 执行接口InterfaceB.process 耗时:2004ms
22:03:43.180 [线程名称-0] INFO DemoTest$InterfaceA - 执行接口InterfaceA.process 耗时:2004ms
22:03:43.190 [main] INFO DemoTest - 执行结果:2 耗时:2020

此方式还可以结合CompletionService可实现异步任务和执行结果分离,大家可以自行搜索实践

强大的CompletableFuture JDK1.8

import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;

@Slf4j
public class DemoTest {

    public static void main(String[] args) throws Exception {
        long beginTime = System.currentTimeMillis();

        CompletableFuture<Integer> interfaceFuturesA = CompletableFuture.supplyAsync(() -> new InterfaceA().process());
        CompletableFuture<Integer> interfaceFuturesB = CompletableFuture.supplyAsync(() -> new InterfaceB().process());
        CompletableFuture<List<Integer>> future = CompletableFuture
                .allOf(interfaceFuturesA, interfaceFuturesB)
                .thenApply((none) -> {
                    List<Integer> dataList = new ArrayList<>(2);
                    try {
                        dataList.add(interfaceFuturesA.get());
                        dataList.add(interfaceFuturesB.get());
                    } catch (Exception e) {
                        log.error("执行异常");
                    }
                    return dataList;
                }).exceptionally(e -> Lists.newArrayList());

        int result = future.get().get(0) + future.get().get(1);
        log.info("执行结果:{} 耗时:{}", result, System.currentTimeMillis() - beginTime);
    }

    @Slf4j
    public final static class InterfaceA {
        Integer result = 1;

        public int process() {
            long beginTime = System.currentTimeMillis();
            try {
                Thread.sleep(2000);
            } catch (Exception e) {
                log.error("InterfaceA.process Exception");
            }
            log.info("执行接口InterfaceA.process 耗时:{}ms", System.currentTimeMillis() - beginTime);
            return result;
        }
    }

    @Slf4j
    public final static class InterfaceB {
        Integer result = 1;

        public int process() {
            long beginTime = System.currentTimeMillis();
            try {
                Thread.sleep(2000);
            } catch (Exception e) {
                log.error("InterfaceB.process Exception");
            }
            log.info("执行接口InterfaceB.process 耗时:{}ms", System.currentTimeMillis() - beginTime);
            return result;
        }
    }
}

执行结果:

22:31:44.822 [ForkJoinPool.commonPool-worker-5] INFO DemoTest$InterfaceB - 执行接口InterfaceB.process 耗时:2005ms
22:31:44.822 [ForkJoinPool.commonPool-worker-3] INFO DemoTest$InterfaceA - 执行接口InterfaceA.process 耗时:2002ms
22:31:44.831 [main] INFO DemoTest - 执行结果:2 耗时:2027

优化时注意点

  • 使用线程池防止内存溢出风险
  • 执行结果容器可自行根据需要设置
  • 接口粒度可根据实际业务情况组合和拆分

相关文章

  • 接口异步调用,接口耗时减少的可不是一点点

    随着业务发展,底层数据量越来越大,业务逻辑也日趋复杂化,某些接口耗时也越来越长,这时候接口就需要进行性能优化了,当...

  • nuxt-asyncData 多个接口异步

    接口同步, 耗时长 接口异步

  • 异步调用Feign接口空指针问题

    异步调用Feign接口空指针问题原因: Feign接口的Request 默认是主线程和子线程不共享的,当异步调用F...

  • 接口性能优化实战

    耗时接口的性能优化 异步并发执行,CompletableFuture,比如查询商品详情接口,需要查各种表,返回一个...

  • OC 中异步顺序加载用法

    实际开发过程中,有可能会用到顺序加载异步的需求,比如先掉A接口,直到A接口调用完成,在调用B接口,以此类推C接口....

  • ES6-new promise用法

    我的理解:优化接口调用重复嵌套繁琐问题,使调用接口异步操作简洁明了。 代码示例: $.ajax(url1,func...

  • Jmeter 通过while Controller循环轮询接口同

    在使用jmeter调用接口时,某些场景需要轮询接口直到接口返回预期的才停止轮询,这种场景在一些异步处理的接口非常常...

  • Spring异步接口

    异步接口的重要性 我们都知道同步调用会阻塞线程,将耗时的工作放到线程池中工作是常识,这对于servlet容器同样适...

  • iOS app性能优化

    避免阻塞主线程耗时操作尽量放进子线程 cache网络数据缓存至本地图片的异步缓存 减少程序启动过程中的任务网络接口...

  • vue学习4

    接口调用方式 原生ajax 基于jQuery的ajax fetch axios 异步 JavaScript的执行环...

网友评论

      本文标题:接口异步调用,接口耗时减少的可不是一点点

      本文链接:https://www.haomeiwen.com/subject/bqktsltx.html