Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在控制器中使用@Async和CompletableFuture是否可以提高api的性能?_Java_Spring_Performance_Asynchronous_Completable Future - Fatal编程技术网

Java 在控制器中使用@Async和CompletableFuture是否可以提高api的性能?

Java 在控制器中使用@Async和CompletableFuture是否可以提高api的性能?,java,spring,performance,asynchronous,completable-future,Java,Spring,Performance,Asynchronous,Completable Future,我试图实现的是,通过使用@Async和CompletableFuture,我可以获得更好的性能吗?通过以这种简单的方式使用多线程,我的RESTApi控制器可以获得更好的性能吗 这是我要做的,这是我的控制器: @PostMapping("/store") @Async public CompletableFuture<ResponseEntity<ResponseRequest<CategoryBpsjResponseDto>>> saveN

我试图实现的是,通过使用@Async和CompletableFuture,我可以获得更好的性能吗?通过以这种简单的方式使用多线程,我的RESTApi控制器可以获得更好的性能吗

这是我要做的,这是我的控制器:

@PostMapping("/store")
@Async
public CompletableFuture<ResponseEntity<ResponseRequest<CategoryBpsjResponseDto>>> saveNewCategoryBPSJ(@Valid @RequestBody InputRequest<CategoryBPSJRequestDto> request) {
    
    CompletableFuture<ResponseEntity<ResponseRequest<CategoryBpsjResponseDto>>> future = new CompletableFuture<>();

    future.complete(ResponseEntity.ok(new ResponseRequest<>("Okay", categoryBPSJService.save(request))));
    return future;
}
我只返回带有JPA连接的简单对象,这样我的请求性能会提高吗?还是我错过了一些可以增加它的东西?或者在我的控制器上有或没有CompletableFuture和@Async都没有区别


*注意:我的项目基于Java13,使用CompletableFuture不会神奇地提高服务器的性能

如果您使用的是通常在Jetty或Tomcat之上构建的ServletAPI,那么每个请求将有一个线程。这些线程的池通常相当大,因此您可以有相当数量的并发请求。在这里,阻止一个请求线程并不是一个问题,因为这个线程无论如何只处理单个请求,这意味着其他请求不会被阻止(除非池中不再有可用的线程)。这意味着,你的IOs可以被阻塞,你的代码可以是同步的

但是,如果您使用的是Netty,那么请求通常会作为消息/事件处理:一个线程可以处理多个请求,这可以减少池的大小(线程非常昂贵)。在这种情况下,线程阻塞是一个问题,因为它可能/将导致其他请求等待IO完成。这意味着,您的IOs必须是非阻塞的,您的代码必须是异步的,这样线程就可以被释放并“同时”处理另一个请求,而不只是等待操作完成。仅供参考,这个反应式堆栈看起来很吸引人,但由于代码库的异步性质,它还有许多其他缺点需要注意

JPA是阻塞的,因为它依赖于JDBC(在IOs上阻塞)。这意味着,在SpringWebFlux中使用JPA没有多大意义,应该避免,因为它违背了“不要阻塞请求线程”的原则。人们已经找到了解决办法(例如,从另一个线程池中运行SQL查询),但这并不能真正解决根本问题:IOs将阻塞,可能/将发生争用。人们正在为Java开发异步SQL驱动程序(例如,和底层特定于供应商的驱动程序),例如,可以在WebFlux代码库中使用这些驱动程序。Oracle也开始开发自己的异步驱动程序ADBA,但这是因为他们专注于光纤via(这可能很快就会完全改变Java中处理并发的方式)

您似乎正在使用SpringMVC,这意味着依赖于每个请求的线程模型。仅仅在代码中删除CompletableFuture并不能改善事情。假设您将所有服务层逻辑委托给默认请求线程池以外的另一个线程池:您的请求线程将可用,是的,但是争用现在将发生在您的另一个线程池上,这意味着您将只是在转移您的问题

某些情况下,延迟到另一个池可能仍然很有趣,例如计算密集型操作(如密码短语散列),或某些会触发大量(阻塞)IO的操作,等等,但请注意争用仍然可能发生,这意味着请求仍然可能被阻塞/等待

如果您确实发现代码库存在性能问题,请先对其进行分析。使用诸如(许多其他可用的)甚至APMs之类的工具(许多其他可用的)。了解瓶颈在哪里,修复问题,重复。尽管如此,一些常见的怀疑是:IOs太多(尤其是JPA),序列化/反序列化太多(尤其是JPA)。基本上,JPA是一个常见的疑点:它是一个强大的工具,但很容易被误解,你需要考虑SQL来正确使用它。我强烈建议在开发时,您可能会感到惊讶。是一个很好的JPA相关资源。读起来也很有趣:


关于您的特定代码片段,假设您使用的是香草Java,而没有Spring的
@Async
支持:

CompletableFuture=newcompletablefuture();
future.complete(ResponseEntity.ok(新的ResponseRequest(“ok”,categoryBPSjsService.save(request)));
回归未来;
这不会使
categoryBPSJService.save(请求)
异步运行。如果您稍微拆分一下代码,它将变得更加明显:

CategoryBpsjResponseDto categoryBPSJ = categoryBPSJService.save(request)
CompletableFuture<ResponseEntity<ResponseRequest<CategoryBpsjResponseDto>>> future = new CompletableFuture<>();
future.complete(ResponseEntity.ok(new ResponseRequest<>("Okay", categoryBPSJ)));
return future;
基本上只是上述语法,请使用或。出于技术上的AOP/代理原因,用
@Async
注释的方法确实需要返回一个可完成的未来,在这种情况下,返回一个已完成的未来是可以的:Spring无论如何都会让它在执行器中运行。服务层通常是“异步”的,但控制器只是在返回的未来进行消费和组合:

CompletableFuture<CategoryBpsjResponseDto> = categoryBPSJService.save(request);
return future.thenApply(categoryBPSJ -> ResponseEntity.ok(new ResponseRequest<>("Okay", categoryBPSJ)));
CompletableFuture=categoryBPSJService.save(请求);
返回future.thenappy(categoryBPSJ->ResponseEntity.ok(新的ResponseRequest(“ok”,categoryBPSJ));
通过调试您的代码,确保它的行为符合您的预期,IDE显示当前被断点阻止的线程



旁注:这是我对阻塞与非阻塞、MVC与WebFlux、同步与异步等的理解的一个简单总结。这相当肤浅,我的一些观点可能不够具体,无法100%正确。

如果您试图“提高性能”(这可能意味着几件事情中的任何一件),您首先需要测量您的应用程序,以确定性能问题在哪里。我认为这不是很有用。如果您在应用服务器中,AS有一个线程池来响应web请求。这里要做的是释放web线程,但将其移动到Spring使用的线程池中。所以对我来说没有优势。可以使用异步
CategoryBpsjResponseDto categoryBPSJ = categoryBPSJService.save(request)
CompletableFuture<ResponseEntity<ResponseRequest<CategoryBpsjResponseDto>>> future = new CompletableFuture<>();
future.complete(ResponseEntity.ok(new ResponseRequest<>("Okay", categoryBPSJ)));
return future;
CompletableFuture<CategoryBpsjResponseDto> future = CompletableFuture.supplyAsync(
    () -> categoryBPSJService.save(request),
    someExecutor
);
return future.thenApply(categoryBPSJ -> ResponseEntity.ok(new ResponseRequest<>("Okay", categoryBPSJ)));
CompletableFuture<CategoryBpsjResponseDto> = categoryBPSJService.save(request);
return future.thenApply(categoryBPSJ -> ResponseEntity.ok(new ResponseRequest<>("Okay", categoryBPSJ)));