V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
yuhongtai114514
V2EX  ›  Java

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

  •  
  •   yuhongtai114514 · 203 天前 · 7208 次点击
    这是一个创建于 203 天前的主题,其中的信息可能已经有所发展或是发生改变。
    因为 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 友们~
    44 条回复    2024-01-03 23:25:42 +08:00
    BBCCBB
        1
    BBCCBB  
       203 天前
    可以先理解下 js 里最开始的 callback hell, 然后再看看 Promise 的出现解决了 js 的什么问题. Promise 可以理解成一个最简单的响应式..

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

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

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

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

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

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

    下次有这种需求,我会选择使用 openresty 或者 apisix ,选择 openresty 用 lua 开发的体验应该也比 gateway 的这个响应式强
    Leviathann
        18
    Leviathann  
       202 天前
    Brian Goetz: "I think Project Loom is going to kill Reactive Programming"
    GiantHard
        19
    GiantHard  
       202 天前
    > 比如在数据流上设定操作符(如 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
        20
    yazinnnn0  
       202 天前
    https://www.reactivemanifesto.org/zh-CN

    响应式和异步非阻塞没啥关系
    Hugehard
        21
    Hugehard  
       202 天前
    不只是看不懂,debug 我都搞不懂,目前在看一个项目,全靠 gpt 理解
    yuhongtai114514
        22
    yuhongtai114514  
    OP
       202 天前 via iPhone
    @BBCCBB 感谢,这就去看看~
    yuhongtai114514
        23
    yuhongtai114514  
    OP
       202 天前 via iPhone
    @b1t ok ~
    yuhongtai114514
        24
    yuhongtai114514  
    OP
       202 天前 via iPhone
    @statumer 好的,非常感谢,看来我过于相信 gpt 了(´_ゝ`),直接绕晕
    yuhongtai114514
        25
    yuhongtai114514  
    OP
       202 天前 via iPhone
    @GiantHard 帮助很大! 我去看看 Rx ,感谢解惑🙏
    yuhongtai114514
        26
    yuhongtai114514  
    OP
       202 天前 via iPhone
    @yazinnnn0 我之前一直以为这两个强关联🥹
    imaple
        27
    imaple  
       202 天前
    确实有点难, 而且很难调试, 爆炸
    cloud107202
        28
    cloud107202  
       202 天前
    unco020511
        29
    unco020511  
       202 天前
    其实 rxjava 更多使用是在界面程序的,比如移动端应用,主线程不能做耗时操作,经常需要使用 callback,需要频繁切换线程.后台我感觉必要性没有那么大
    vivisidea
        30
    vivisidea  
       202 天前
    subscribe / subscribeOn 调试起来要疯,我们之前有个项目试点了一下响应式,写的人觉得很爽,其它开发一脸懵,维护很麻烦,后来还是抛弃了
    Huelse
        31
    Huelse  
       202 天前
    不如学函数式编程,其核心思想要普遍的多。
    rrfeng
        32
    rrfeng  
       202 天前
    当年写 angular 强行学习了一下 rxjs ,学起来太难,但是会了确实很好用(然而已经忘光了)。

    前提是 js ,java/go 还是协程走起吧。
    ychost
        33
    ychost  
       202 天前
    首先得理解什么是 IO ,IO 底层如何实现「同步非阻塞」的,然后再来看 flatMap 操作符的用处,如果不用 flatMap 自己该如何处理这些 IO 回调,如果业务里面 IO 少的话没必要上 reactor
    mxT52CRuqR6o5
        34
    mxT52CRuqR6o5  
       202 天前 via Android
    学过 rxjs 也实际应用过,没觉得有多好用(没有必要的话就不要去用),但如果有复杂的异步场景的话,不用 rx 写起来感觉就是寸步难行
    Dlin
        35
    Dlin  
       202 天前 via Android
    个人也觉得响应式是一种编程思想。是某个事务满足触发操作时触发的同步回调。每个 filter 只是这次触发中的执行过程中的一部分。说它异步,其实只是这一过程并非是人为有意去调用的。而是系统自己去调用的(subscribe)
    comingnine
        36
    comingnine  
       202 天前 via Android
    感觉解藕真不好调试
    xarthur
        37
    xarthur  
       202 天前 via iPhone
    其实你需要去了解一些函数式编程,响应式只是很自然的引用……
    zhuangzhuang1988
        38
    zhuangzhuang1988  
       202 天前 via Android
    https://www.bennadel.com/blog/4519-replacing-rxjs-with-a-state-machine-in-javascript.htm
    想象成状态机试试
    不过状态机会要写很多代码 rx 帮忙解决了
    ma836323493
        39
    ma836323493  
       201 天前
    看看郭神 的 第一行代码, 了解这个应该轻松电吧
    f14g
        40
    f14g  
       201 天前 via Android
    以前也是不理解这个,后来学校教 Verilog 的时候遇到了“线变量”这种东西,当时就理解了“响应式编程”了。
    nothingistrue
        41
    nothingistrue  
       201 天前   ❤️ 2
    六,响应式编程,对应的编程概念是「流」,现实概念有个跟起非常像的,「流水线」。如果要搞这个,首先要把「流」搞清楚。Java8 的 Stream 可以用来入门。Kettle 、Spring Batch 可以用来练手。你最起码是 kettle 或者 Spring Batch (高级流应用,不能是一个处理器转发然后又回到普通代码去处理了) 用得比较熟悉了,才能去接触响应式编程。另外,你也可以直接从函数式编程、数据流,这些数学理论入手,不过前提是要先清空 C 、C++、Java 等全部常规编程习惯。

    一到五跑题了,留着备用看吧。

    一,同异步跟是否阻塞,不是一词两用,而是有关联的两个概念。

    二,阻塞针对的不是当前过程,而是使用同一资源的多个过程之间的协作方式。通常都是 IO 比计算慢,故常见的阻塞是针对 IO 的阻塞。一个 IO 通道,如果只允许同时最多一个过程使用它,在该过程使用它期间其他过程只能等,那么这就是阻塞的。如果允许同时多个过程使用它,那么这是非阻塞的。

    三,同步异步,针对的是调用者和被调用者之间的协作过程。如果被调用者不做完就不回复,同时调用者还一直等着它,那么这是同步的。如果被调用者没处理完就提前做个特殊回复,同时调用者认可这种特殊回复,那么这是异步调用。如果调用者这收到异步特殊回复之后,又再继续等待这个特殊回复转换成完整回复,那么这是异步之后的回转同步,或者,整体上来说,这还是同步调用。

    四,再往外看调用者、非调用者的宿主程序,这时候同异步跟阻塞有了关联。如果把调用者宿主程序认为资源,调用关系——被调用者的执行行为认为处理过程,那么同步调用是阻塞的,异步调用是非阻塞的。

    五,同步还是异步,技术上由被调用者决定,但业务上由有调用者决定。如果调用者实时关心回复结果,那么它永远要是同步调用,即使被调用者技术上异步,最终也要通过异步转回同步来变成同步。异步编程中,如何异步从来都不是关键,如何异步转会同步,获取去掉不必要的业务同步,才是关键。
    yuhongtai114514
        42
    yuhongtai114514  
    OP
       201 天前
    @xarthur ok~之前还没正式看过函数式调用,只知道是把函数传来传去
    4kingRAS
        43
    4kingRAS  
       199 天前
    你真正要看阻不阻塞要看线程 id ,当前代码运行在哪个线程
    hdfg159
        44
    hdfg159  
       115 天前 via iPhone
    rxjava 玩一轮,你就懂了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   950 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 32ms · UTC 22:49 · PVG 06:49 · LAX 15:49 · JFK 18:49
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.