Spring MVC(异步)与 Spring WebFlux

问题描述 投票:0回答:3

我正在尝试了解 Spring WebFlux。到目前为止我发现的东西在核心都是反应式的,没有 Servlet API,每个请求没有线程,HTTP 2,服务器推送,application/stream+json。

但是 Spring MVC 中的异步调用有什么区别呢?我的意思是,在 Spring MVC 中,当您返回 Future、DefferedResult 等时,您会在单独的线程中执行请求处理程序(控制器方法)中获得逻辑,因此您也可以从节省用于分派请求的线程池资源中受益。

那么您能强调一下与此相关的差异吗?为什么 WebFlux 在这里更好?

非常感谢您的宝贵时间!

java spring spring-mvc spring-webflux
3个回答
56
投票

Servlet 异步模型在容器线程(1 个 Servlet 请求/线程模型)和应用程序中的请求处理之间引入了异步边界。处理可以发生在不同的线程上或等待。最后,您必须分派回容器线程并以阻塞方式读/写(

InputStream
OutputStream
本质上是阻塞API)。

使用该模型,您需要许多线程来实现并发(因为其中许多线程可能会因等待 I/O 而被阻塞)。这会消耗资源,并且可能是一种权衡,具体取决于您的用例。

使用非阻塞代码,您只需要几个线程即可同时处理大量请求。这是一种不同的并发模型;与任何模型一样,它有利也有弊。

有关该比较的更多信息,应该对这个 Servlet 与 Reactive stacks talk 感兴趣。


11
投票

Servlet API 是阻塞 I/O,每个 HTTP 请求需要 1 个线程。 Spring MVC 异步依赖于 Servlet API,它仅提供容器线程和请求处理线程之间的异步行为,但不提供端到端的异步行为。

Spring WebFlux 另一方面,通过使用 HTTP 套接字并通过套接字一次推送数据块,通过固定数量的线程实现并发。这种机制称为“事件循环”,这是由“Node.js”流行起来的想法。这种方法具有可扩展性和弹性。 Spring 5 的 spring-webflux 使用事件循环方法来提供异步行为。 更多内容可以阅读

Servlet 与响应式


0
投票

基本上,我们可以说线程是执行代码的“小地方”。

虚拟线程

忘记线程是昂贵且稀缺的资源。虚拟线程通过称为协程的范例解决了线程上浪费时间的问题。虚拟线程仍然是线程,它们的行为就像线程一样,不同之处在于它们不再像平台线程那样由操作系统管理,而是由 JVM 管理。现在,对于每个平台线程,我们将有一个关联的虚拟线程池。每个平台线程有多少个虚拟线程?需要多少就多少。每个 JVM 可以拥有数百万个虚拟线程。 使用 Java 21 和 Spring Boot 3.2+,您只需要 application.properties 中的一个参数

spring.threads.virtual.enabled=false

您的应用程序已经在使用虚拟线程了!

之前,每个请求都有一个平台线程。现在,对于每个需要执行的任务,平台线程都会将该任务委托给虚拟线程。

不是平台线程自己执行请求,而是将其委托给虚拟线程,当此执行遇到阻塞 I/O 时,Java 通过将虚拟线程上下文放置在堆内存中来暂停此执行,平台线程是空闲的来执行新任务。一旦虚拟线程准备好,它就会恢复执行。

虚拟线程是守护线程,因此它们不会阻止应用程序关闭,这与非守护线程不同,在非守护线程中,线程结束时应用程序也随之结束。

切勿使用泳池

当我们谈论线程池或连接池时,我们隐含地在说:我的资源是有限的,所以我需要管理它的使用。但是虚拟线程很丰富,不应该使用虚拟线程池。 我们拥有的虚拟线程的数量等于我们同时执行的活动的数量。简而言之,对于每个并发任务,您必须实例化一个新的虚拟线程。

© www.soinside.com 2019 - 2024. All rights reserved.