为什么该线程池不能同时执行HTTP请求?

时间:2018-10-21 16:12:10

标签: java http threadpool executorservice resttemplate

我写了几行代码,这些代码将向我的机器上运行的服务发送50个HTTP GET请求。服务将始终sleep 1秒,并返回带有空主体的HTTP状态代码200。如预期的那样,代码运行了大约50秒钟。

为了加快速度,我尝试创建一个具有4个线程的ExecutorService,以便始终可以同时向我的服务发送4个请求。我希望代码能运行约13秒钟。

final List<String> urls = new ArrayList<>();
for (int i = 0; i < 50; i++)
    urls.add("http://localhost:5000/test/" + i);

final RestTemplate restTemplate = new RestTemplate();

final List<Callable<String>> tasks = urls
        .stream()
        .map(u -> (Callable<String>) () -> {
            System.out.println(LocalDateTime.now() + " - " + Thread.currentThread().getName() + ": " + u);
            return restTemplate.getForObject(u, String.class);
        }).collect(Collectors.toList());

final ExecutorService executorService = Executors.newFixedThreadPool(4);

final long start = System.currentTimeMillis();
try {
    final List<Future<String>> futures = executorService.invokeAll(tasks);

    final List<String> results = futures.stream().map(f -> {
        try {
            return f.get();
        } catch (InterruptedException | ExecutionException e) {
            throw new IllegalStateException(e);
        }
    }).collect(Collectors.toList());
    System.out.println(results);
} finally {
    executorService.shutdown();
    executorService.awaitTermination(10, TimeUnit.SECONDS);
}

final long elapsed = System.currentTimeMillis() - start;
System.out.println("Took " + elapsed + " ms...");

但是-如果您查看调试输出的秒数-似乎前四个请求是同时执行的,而所有其他请求则是依次执行的:

2018-10-21T17:42:16.160 - pool-1-thread-3: http://localhost:5000/test/2
2018-10-21T17:42:16.160 - pool-1-thread-1: http://localhost:5000/test/0
2018-10-21T17:42:16.160 - pool-1-thread-2: http://localhost:5000/test/1
2018-10-21T17:42:16.159 - pool-1-thread-4: http://localhost:5000/test/3
2018-10-21T17:42:17.233 - pool-1-thread-3: http://localhost:5000/test/4
2018-10-21T17:42:18.232 - pool-1-thread-2: http://localhost:5000/test/5
2018-10-21T17:42:19.237 - pool-1-thread-4: http://localhost:5000/test/6
2018-10-21T17:42:20.241 - pool-1-thread-1: http://localhost:5000/test/7
...
Took 50310 ms...

因此,出于调试目的,我将HTTP请求更改为一个sleep调用:

// return restTemplate.getForObject(u, String.class);
TimeUnit.SECONDS.sleep(1);
return "";

现在代码可以按预期工作:

...
Took 13068 ms...

所以我的问题是,为什么带有sleep调用的代码能按预期工作,而带有HTTP请求的代码却不能按预期工作?以及如何使其表现出预期的效果?

1 个答案:

答案 0 :(得分:2)

从信息中,我可以看到这是最可能的根本原因:

  

您发出的请求是并行完成的,但是满足这些请求的 HTTP服务器 一次处理1个请求

因此,当您开始发出请求时, headerText: { color: 'white', fontSize: 30, fontFamily: 'Lobster' }, 会同时获得前4个。

但是 HTTP服务器可以响应,一次请求一个,即每个请求1秒后。

现在,当满足第一个请求时,执行者服务会选择另一个请求并将其触发,直到最后一个请求。

一次

4个请求在HTTP服务器上被阻止,它们被依次依次连续提供服务。

要获得此理论的executor service fires up the requests concurrently,您可以做的是使用消息传递服务(队列),该服务可以同时从4个通道接收测试。那应该减少时间。