[英]Async call of a FeignClient Springboot with CompletableFuture
[英]SpringBoot-2.1.3: Parallel Methods Invocation with @Async with CompletableFuture
下面是我的代碼,我在其中嘗試並行化 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
}
}
我得到了預期的結果,但注意到調用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
我想當我們將CompletableFuture
用於帶有@EnableAsync
配置的@Async
方法時,這些方法將被分配一個新線程來執行它們,有人可以解釋一下這是並行方法調用的預期行為嗎? 我的配置有什么問題嗎? 或者,如果這是我們在同一線程中執行caller
方法和async
時如何實現並行性的預期行為?
可以在代碼中進行所需的更改。
第 1 步:執行多線程的第一步是正確設置線程池配置。
這是一個如何設置線程大小的示例
@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;
}
第二步:使用@Async注解
首先,讓我們回顧一下規則。
有關@Async 的更多信息,您可以通過
解決方案:
@Async("taskExecutor")
之類的 Bean 名稱標記您的注釋任何一種方式都適合你。
您應該設置線程池大小以控制線程數:
final ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(2);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("CarThread-");
我建議檢查一些事實:
OrderStatsService
類是static
的嗎?它是由 Spring 管理的Bean
嗎?Bean
的@Async
方法必須直接從它的調用者調用。 您在OrderStatsService
( Bean
-如果您已經這樣做了)中擁有的是調用non-@Async
@Async 方法,然后調用@Async
方法。 以我的經驗,這不會給你預期的行為。如果我是一個愚蠢的笨蛋,請隨時糾正我。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.