[英]SpringBoot-2.1.3: Parallel Methods Invocation with @Async with CompletableFuture
Below is my code in which am trying to parallelize the 4 methods invocations since each method is independent of each other and performs some memory intensive statistical operations.下面是我的代码,我在其中尝试并行化 4 个方法调用,因为每个方法彼此独立并执行一些内存密集型统计操作。
@EnableAsync
@Configuration
public class Config {
@Bean(name = "threadPoolTaskExecutor")
public Executor threadPoolTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.initialize();
return executor;
}
}
class OrderStatsService{
public CumulativeStats compute() {
log.info("CumulativeResult compute started at " + System.currentTimeMillis() + ", Current Thread Name: " + Thread.currentThread().getName() + ", Current Thread ID: " + Thread.currentThread().getId());
List<Order> orders = getOrders();// API Call to fetch large set of orders size could be around 100k
CumulativeResult cumulativeResult = new CumulativeResult();
CompletableFuture<Long> stats1 = getStats1(orders);
CompletableFuture<List<String>> result2 = getStats2(orders);
CompletableFuture<Double> result3 = getStats3(orders);
CompletableFuture<Map<String,String>> result4 = getStats4(orders);
cumulativeResult.setStats1(stats1);
cumulativeResult.setStats2(stats2);
cumulativeResult.setStats3(stats3);
cumulativeResult.setStats4(stats4);
return cumulativeResult;
}
@Async("threadPoolTaskExecutor")
public CompletableFuture<Long> getStats1(var orders) {
log.info("getStats1 started at " + System.currentTimeMillis() + ", Current Thread Name: " + Thread.currentThread().getName() + ", Current Thread ID: " + Thread.currentThread().getId());
//computes some stats
}
@Async("threadPoolTaskExecutor")
public CompletableFuture<List<String>> getStats2(var orders) {
log.info("getStats2 started at " + System.currentTimeMillis() + ", Current Thread Name: " + Thread.currentThread().getName() + ", Current Thread ID: " + Thread.currentThread().getId());
//computes some stats
}
@Async("threadPoolTaskExecutor")
public CompletableFuture<Double> getStats3(var> orders) {
log.info("getStats3 started at " + System.currentTimeMillis() + ", Current Thread Name: " + Thread.currentThread().getName() + ", Current Thread ID: " + Thread.currentThread().getId());
//computes some stats
}
@Async("threadPoolTaskExecutor")
public CompletableFuture<Map<String,String>> getStats4(var orders) {
log.info("getStats4 started at " + System.currentTimeMillis() + ", Current Thread Name: " + Thread.currentThread().getName() + ", Current Thread ID: " + Thread.currentThread().getId());
//computes some stats
}
}
I'm getting the expected result but noticed that the main thread which is invoking the compute()
is executing the other 4 methods getStats1
, getStats2
, getStats3
, getStats4
methods as well.我得到了预期的结果,但注意到调用compute()
的主线程也在执行其他 4 个方法getStats1
、 getStats2
、 getStats3
、 getStats4
方法。
CumulativeResult compute started at 1655783237437, Current Thread Name: http-nio-8080-exec-1, Current Thread ID: 28
getStats1 started at 1655783238022, Current Thread Name: http-nio-8080-exec-1, Current Thread ID: 28
getStats2 started at 1655783238024, Current Thread Name: http-nio-8080-exec-1, Current Thread ID: 28
getStats3 started at 1655783463062, Current Thread Name: http-nio-8080-exec-1, Current Thread ID: 28
getStats4 started at 1655783238085, Current Thread Name: http-nio-8080-exec-1, Current Thread ID: 28
I thought when we use CompletableFuture
for @Async
methods with @EnableAsync
config those methods would be assigned a new thread for their execution, can someone please explain is this is the expected behavior or not for parallel methods invocation?我想当我们将CompletableFuture
用于带有@EnableAsync
配置的@Async
方法时,这些方法将被分配一个新线程来执行它们,有人可以解释一下这是并行方法调用的预期行为吗? Is there anything wrong with my config?我的配置有什么问题吗? Or if this is the expected behavior how the parallelism is achieved when we are executing the caller
method and the async
in same thread?或者,如果这是我们在同一线程中执行caller
方法和async
时如何实现并行性的预期行为?
The required changes can be done in the code.可以在代码中进行所需的更改。
Step 1: The very first step to executing multithreading is to set up the thread pool config properly.第 1 步:执行多线程的第一步是正确设置线程池配置。
Here is an example of how you can set it up the size of the thread这是一个如何设置线程大小的示例
@Configuration
@EnableAsync
public class ThreadPoolConfiguration {
@Bean(name = "taskExecutor")
public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
threadPoolTaskExecutor.setThreadNamePrefix("thread-");
threadPoolTaskExecutor.setCorePoolSize(100);
threadPoolTaskExecutor.setMaxPoolSize(120);
threadPoolTaskExecutor.setQueueCapacity(100000);
threadPoolTaskExecutor.initialize();
return threadPoolTaskExecutor;
}
Step 2: Using @Async annotation第二步:使用@Async注解
First, let's go over the rules.首先,让我们回顾一下规则。
For more information on @Async you can go through有关@Async 的更多信息,您可以通过
Solutions :解决方案:
@Async("taskExecutor")
用@Async("taskExecutor")
之类的 Bean 名称标记您的注释Either of the ways will work for you.任何一种方式都适合你。
You should set thread pool size for controlling thread count:您应该设置线程池大小以控制线程数:
final ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(2);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("CarThread-");
Multi-Threading in Spring Boot Using CompletableFuture Spring Boot 中的多线程使用 CompletableFuture
I would recommend checking some facts:我建议检查一些事实:
OrderStatsService
class static
and is it a Bean
managed by Spring?您的OrderStatsService
类是static
的吗?它是由 Spring 管理的Bean
吗?@Async
methods of a Bean
have to be invoked directly from it's caller. Bean
的@Async
方法必须直接从它的调用者调用。 What you are having in your OrderStatsService
( Bean
-if you've done this already) is calling the non-@Async
method, followed by invoking the @Async
methods.您在OrderStatsService
( Bean
-如果您已经这样做了)中拥有的是调用non-@Async
@Async 方法,然后调用@Async
方法。 In my experience, this won't give you the expected behaviour.以我的经验,这不会给你预期的行为。Feel free to correct me if I'm being a dummy dumb dumb.如果我是一个愚蠢的笨蛋,请随时纠正我。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.