同时处理多请求

Posted xuwenjin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了同时处理多请求相关的知识,希望对你有一定的参考价值。

在工作中遇到同时向多个服务请求的场景,在此将自己的研究过程记录一下

模拟三个请求requestA、requestB、requestC:

@Service
public class ParallelService 

    public String requestA() 
        try 
            TimeUnit.MILLISECONDS.sleep(1000);
         catch (InterruptedException e) 
            e.printStackTrace();
        
        return "A";
    

    public String requestB() 
        try 
            TimeUnit.MILLISECONDS.sleep(2000);
         catch (InterruptedException e) 
            e.printStackTrace();
        
        return "B";
    

    public String requestC() 
        try 
            TimeUnit.MILLISECONDS.sleep(2500);
         catch (InterruptedException e) 
            e.printStackTrace();
        
        return "C";
    

建立一个测试类ParallelController,request方法用来模拟请求不同服务:

@Slf4j
@RestController @RequestMapping(
"parallel") public class ParallelController @Autowired private ParallelService parallelService; private String request(int index) if (index == 0) return parallelService.requestA(); if (index == 1) return parallelService.requestB(); if (index == 2) return parallelService.requestC(); return null;

接下来,就开始尝试不同的请求方式:

 

串行(传统方式)

   /**
     * 串行(传统请求)
     */
    @GetMapping("/test1")
    public void test1() 
        long start = System.currentTimeMillis();
        List<String> list = new ArrayList<>();
        IntStream.range(0, 3).forEach(index -> 
            list.add(request(index));
        );
        log.info("串行,响应结果:,响应时长:", Arrays.toString(list.toArray()), System.currentTimeMillis() - start);
    

使用JMeter进行压测,压测参数如下:

技术图片

创建30个线程,在20秒之内循环请求,结果:

技术图片

技术图片

从控制台结果可以看到:请求是顺序执行,所以结果都是[A, B, C],响应时长也很稳定

从JMeter结果可以看到:平均响应时长:5805ms,最小响应时长:5507ms,最大响应时长:6497ms,QPS:5.0/sec

 

并行

并行采用的是java8的语法流,利用多核处理器同时去请求,当获取所有请求结果后才终止

   /**
     * 并行请求
     */
    @GetMapping("/test2")
    public void test2() 
        long start = System.currentTimeMillis();
        List<String> list = new ArrayList<>();
        IntStream.range(0, 3).parallel().forEach(index -> 
            list.add(request(index));
        );
        log.info("java8并行,响应结果:,响应时长:", Arrays.toString(list.toArray()), System.currentTimeMillis() - start);
    

使用jmeter同样的参数压测,结果:

技术图片

技术图片

从控制台结果可以看到:请求是独立执行没有顺序,所以结果是不确定的,响应时长很不稳定

从JMeter结果可以看到:平均响应时长:16648ms,最小响应时长:2513ms,最大响应时长:36052ms,QPS:1.3/sec

 

 多线程

 多线程的处理方式是,创建多个线程,分别去请求,当获取所有请求结果后才终止

   /**
     * 多线程请求
     */
    @GetMapping("/test3")
    public void test3() 
        long start = System.currentTimeMillis();

        List<String> list = new ArrayList<>();
        List<Future<String>> futureList = new ArrayList<>();
        ExecutorService executor = Executors.newFixedThreadPool(3); // 开启3个线程
        IntStream.range(0, 3).forEach(index -> 
            Future<String> task = executor.submit(() -> request(index));
            futureList.add(task);
        );
        for (Future<String> future : futureList) 
            try 
                // 如果任务执行完成,future.get()方法会返回Callable任务的执行结果。
                // future.get()方法会产生阻塞,所有线程都阻塞在这里,当获取到一个结果后,才执行下一个
                list.add(future.get());
             catch (Exception e) 
                log.error(e.getMessage(), e);
            
        
        // 停止接收新任务,原来的任务继续执行
        executor.shutdown();

        log.info("多线程,响应结果:,响应时长:", Arrays.toString(list.toArray()), System.currentTimeMillis() - start);
    

技术图片

技术图片

从控制台结果可以看到:请求是顺序执行的,结果都是[A, B, C],响应时长比较稳定

从JMeter结果可以看到:平均响应时长:2505ms,最小响应时长:2503ms,最大响应时长:2519,QPS:11.4/sec

 

结论:

1、串行处理多请求,代码很简单,响应时长是每个请求时长的总和,很稳定但是效率不高

2、使用java8并行处理,代码很简单,响应时长很不稳定,效率也不高,不建议使用

3、使用多线程处理时,代码复杂,响应时长为单个请求中时长最长的那个,效率很高,推荐使用

 

以上是关于同时处理多请求的主要内容,如果未能解决你的问题,请参考以下文章

多线程

Servlet容器如何同时来处理多个请求

(05)使用DeferredResult多线程异步处理请求

(05)使用DeferredResult多线程异步处理请求

python里同时发送多个http请求怎么弄

java高级之多线程