Project Reactor源码分析-subscribeOn

相关示例源码:github.com/chentianmin…

功能分析

public final Flux<T> subscribeOn(Scheduler scheduler, boolean requestOnSeparateThread)

在subscribe的时候进行线程切换,subscribeOn()使得它上游的订阅阶段以及整个消费阶段异步执行

各参数含义如下:

  1. scheduler:线程切换的调度器,Scheduler用来生成实际执行异步任务的Worker
  2. requestOnSeparateThread:是否需要在Worker上执行request()请求,默认true。在慢Publisher、快Consumer场景中可能导致长时间阻塞,可将requestOnSeparateThread设置成false解决这个问题。

代码示例

@Test
public void testBlock() {
    delayPublishFlux(1000, 1, 10)
            .doOnRequest(i -> logLong(i, "request"))
            .subscribeOn(Schedulers.newElastic("subscribeOn"))
            .publishOn(Schedulers.newElastic("publishOn"), 2)
            .subscribe(i -> logInt(i, "消费"));
    sleep(10000);
}

在红框时间段内,消费者被阻塞了!

requestOnSeparateThread设置成false:恢复正常

下面我们从源码角度分析subscribeOn()操作符,顺便探究一下上述问题发生的原因。

源码分析

首先看一下subscribeOn()操作符在装配阶段做了什么,直接查看Flux#subscribeOn()源码。

Flux#subscribeOn()

装配阶段重点是创建了FluxSubscribeOn对象,该类同样实现了OptimizableOperator接口。

在分析publishOn()的时候,我们已经知道此时在subscribe()阶段会调用FluxSubscribeOn#subscribeOrReturn()方法。

FluxSubscribeOn#subscribeOrReturn()

  1. 创建了SubscribeOnSubscriber对象,它同时是一个任务。
  2. 在当前线程调用下游onSubscribe()方法。
  3. 使用Woker异步执行SubscribeOnSubscriber任务,实际执行SubscribeOnSubscriber#run()方法。

SubscribeOnSubscriber#run()

继续调用了上游的Publisher#subscribe()方法,执行订阅。后续肯定会调用到SubscribeOnSubscriber#onSubscribe()方法。

SubscribeOnSubscriber#onSubscribe()

重点是调用了requestUpstream()方法。实际上,在request()中,也可能调用requestUpstream()

SubscribeOnSubscriber#requestUpstream()

这里的重点是:由当前线程还是Worker向上游请求数据

  1. requestOnSeparateThread=false:肯定由当前线程执行。
  2. requestOnSeparateThread=true:取决于当前线程是否与执行subscribe()操作是同一线程。

对于前面的例子,requestOnSeparateThread=true时:

  1. 执行onSubscribe()方法时,当前线程与执行subscribe()操作是同一线程,直接由当前线程继续向上游请求数据。
  2. 执行request()方法时,当前线程变成了publishOn线程,此时由Worker向上游请求数据。而问题正是出现这里,当前的Worker还在生产数据,新提交的任务根本没有线程来执行。request被阻塞住,下游的消费者自然不会消费数据。

这其实还跟elasticScheduler(弹性线程池)有关,它底层是由单线程池组成的,下一篇文章会深入分析。

requestOnSeparateThread=false时,由当前线程(publishOn)继续向上游请求数据,因此不会造成阻塞。

消费阶段

subscribeOn操作符的消费阶段实现简单,都是直接将元素下发给下游。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Reactor 是一个高性能的服务器网络库,广泛应用于高并发的网络通信领域。对于理解 Reactor码,需要从以下几个方面进行分析。 首先是 Reactor 的核心组件-事件循环。事件循环是 Reactor 架构的核心,它负责监听网络事件,接收和处理客户端请求。通过分析事件循环的码,可以了解其如何通过底层的 event-driven 处理模式,实现高效的事件处理和多路复用。 其次是 Reactor 的线程模型。Reactor 采用多线程模型,通过线程池来实现并发处理。分析线程模型的码可以了解 Reactor 如何管理线程,如何实现任务的调度和分发。 然后是 Reactor 的事件处理机制。Reactor 使用事件驱动的方式来处理网络事件,通过注册事件和回调函数的方式,实现网络事件和处理逻辑的解耦。通过分析事件处理机制的码,可以了解 Reactor 如何注册和分发事件,以及如何管理事件的生命周期。 此外,还需要分析 Reactor 的网络协议处理部分。Reactor 作为一个网络服务器库,需要支持各种网络协议的处理,如 HTTP、TCP、WebSocket 等。通过分析网络协议处理部分的码,可以了解 Reactor 如何解析和处理这些协议。 最后,还需要分析 Reactor 的性能优化部分。Reactor 的设计目标是高性能,在码中必然会包含一些性能优化的实现。分析性能优化部分的码,可以了解 Reactor 如何提高网络通信的效率,如何减少资消耗。 总之,React的分析需要从事件循环、线程模型、事件处理机制、协议处理和性能优化等方面进行,通过深入分析这些方面的码,可以更加全面地理解和掌握 Reactor 的原理和实现方式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值