响应式编程确实有点看不懂

2023-10-07 23:38:24 +08:00
 yuhongtai114514
因为 spring cloud gateway 里用了 project reactor 所以就去研究了一番,但是越看越模糊,只知道它的一些用法,比如在数据流上设定操作符(如 flatMap),然后当调用 subscribe 时,这一系列操作符就会被执行。但这个和普通的回调有什么区别呢,为啥说它是异步非阻塞的?

再比如在 spring cloud gateway 里,filter 返回的都是 Mono,当 reactory-netty 收到网络请求时,调用 subscribe ,触发 filter 返回的 Mono 中设定的一系列操作。但是实验了一下,发现 filter 之间也是串行阻塞的:
[在一个 filter 返回的 Mono 的 flatMap 中写下 Thread.sleep(2000L),发现在该 filter 后面的所有 filter 也被阻塞了。但是 gpt 告诉我 filter 之间可以是并行的,因为用了 project reactor ]

想问问这是为啥,感觉始终没有正确理解响应式编程,想问问 v 友们~
7686 次点击
所在节点    Java
44 条回复
BBCCBB
2023-10-07 23:50:59 +08:00
可以先理解下 js 里最开始的 callback hell, 然后再看看 Promise 的出现解决了 js 的什么问题. Promise 可以理解成一个最简单的响应式..

一定程度上解决了 callback hell, 然后加了一些方便开发的 operator 方法.

不建议看这个东西.. 协程才是正路.
b1t
2023-10-08 00:26:53 +08:00
我看 Spring Cloud Gateway 的时候跟你的感觉是一模一样的,然后我就放弃了
b1t
2023-10-08 00:28:28 +08:00
op 如果找到响应式编程的学习方法,记得 @一下我(逃
statumer
2023-10-08 02:32:16 +08:00
Project Reactor 这些东西就是 monad 在 Java 里的实现。需要这个东西的根本原因是 Java 没有协程,非得用纯函数这种不自然的形式构造状态机。
现在没什么学的必要了,如果进展理想的话协程在 Java 世界中会迅速普及。
btw ,回复一下主楼里的问题,你转述的 gpt 的说法是完全错误的,可以自己找本书看或者看 Project Reactor 的 reference ,第三章很好地阐释了基本思想。
weijancc
2023-10-08 08:08:29 +08:00
在 Spring Cloud Gateway 上开发的代码看着真恶心
SilenceLL
2023-10-08 08:19:40 +08:00
原来大家都看着难受,说明是真的难受
iOCZ
2023-10-08 08:34:30 +08:00
不要过分依赖 GPT ,它撒起谎来还有板有眼的
chendy
2023-10-08 08:55:00 +08:00
可以在业务不复杂,对性能又有一些要求的场景使用
不能用同步语法写异步就是坐大牢
iovekkk
2023-10-08 08:55:07 +08:00
按我的理解,响应式编程的意义就是可以把某一个代码块或者函数当做参数,而这一段代码块或者函数的逻辑,可以放到任何地方去实现
mgcnrx11
2023-10-08 09:09:49 +08:00
因为 op 把“响应式 Reactive” 和 “异步非阻塞” 的概念 混淆为 它两个是一个意思了

Project Reactor 的响应式里面,当 subscribe 时,一系列的操作会一个接着一个去执行。但这些操作都是我们自己写的代码,还是需要确保这里自己写的代码是“非阻塞”的才行。否则,就会像你举例的一样,sleep(2000L)后发现阻塞了。
还有的是,除非显式的调用 publishOn / subscribeOn 等方法呢,否则都是在调用 subscribe 的当前线程上执行的。也就会造成该线程被 sleep 阻塞起来的感觉

> 但是 gpt 告诉我 filter 之间可以是并行的

这是错误的
afeiche
2023-10-08 09:13:06 +08:00
spring 那一套和阻塞线程参合在一起,不太好理解,你可以看看 vert.x ,参考 nodejs 搞的,理解起来会容易一点,我没看你过 project reactor ,估计和 vert.x 差不多,底层应该都是 netty 。
ccde8259
2023-10-08 09:14:43 +08:00
想搞响应式编程的话,以生产者-消费者模型为基础,得先入门一下函数式编程,再开始理解值容器也就是 Monad……太难了还是别学了
des
2023-10-08 09:19:33 +08:00
我还以为只有我一个人是这样呢,看的难受
msaionyc
2023-10-08 09:25:42 +08:00
理解起来确实费劲,从声明,订阅( subscribe ),请求,执行,正向->逆向->正向->逆向,最后又到正向执行,太绕了。
而且也不好 debug
Helsing
2023-10-08 09:34:53 +08:00
RxJava 和 Reactor 的思想是类似的,推荐一篇写的很好的关于 RxJava 的文章,希望对你有帮助:

https://juejin.cn/post/6844903670203547656
srx1982
2023-10-08 09:47:49 +08:00
简单的需求还行,如果需求复杂,还要在不同阶段读取多种数据源,那就麻烦了
mikasa1024
2023-10-08 10:08:49 +08:00
之前基于 srping gateway 开发了一个网关管理系统,感受就是业务很难写,到最后只是连着数据库做了个简单的增删查改,然后和网关路由同步起来

下次有这种需求,我会选择使用 openresty 或者 apisix ,选择 openresty 用 lua 开发的体验应该也比 gateway 的这个响应式强
Leviathann
2023-10-08 10:31:19 +08:00
Brian Goetz: "I think Project Loom is going to kill Reactive Programming"
GiantHard
2023-10-08 10:52:44 +08:00
> 比如在数据流上设定操作符(如 flatMap),然后当调用 subscribe 时,这一系列操作符就会被执行。但这个和普通的回调有什么区别呢

没有区别,这些操作符就是在帮助你设置回调函数

> 为啥说它是异步非阻塞的

因为 Operator 的执行线程可以由 Scheduler 决定,所以说 Rx (ReactiveX, 响应式编程 API) 可以实现异步非阻塞

https://projectreactor.io/docs/core/release/api/reactor/core/scheduler/Scheduler.html

> 一个 filter 返回的 Mono 的 flatMap 中写下 Thread.sleep(2000L),发现在该 filter 后面的所有 filter 也被阻塞了

Thread.sleep 是「阻塞的 api 」,你可以试试使用 Rx 的 delay https://projectreactor.io/docs/core/release/api/reactor/core/publisher/Mono.html#delay-java.time.Duration-

除了 Thread.sleep 之外,Java 世界中有很多库的 API 都是阻塞的,要在 Rx 世界中流畅使用,得自己找对应的 Rx 实现
yazinnnn0
2023-10-08 11:57:04 +08:00
https://www.reactivemanifesto.org/zh-CN

响应式和异步非阻塞没啥关系

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/979656

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX