Reactor 3 Reference Guide - 选译 (1)

About the Documentation

本节简要概述了Reactor参考文档。不需要一行一行地阅读本指南,每一节都是独立的,尽管他们经常互相引用。

Getting Started

Introducing Reactor

Reactor是JVM上的完全非阻塞的响应式编程框架,支持有效的需求管理(通过背压的方式)。它直接与Java 8的函数式API集成,特别是CompletableFuture、Stream和Duration。它提供了可组合的异步序列(asynchronous sequence)API:Flux(用于[N]个元素)和Mono(用于 [0|1]个元素)。广泛实现了Reactive Streams
使用reactor-netty,Reactor也支持非阻塞的进程间通信。配合微服务架构,Reactor Netty为HTTP(包括Websockets)、TCP和UDP提供了背压的网络引擎。完全支持响应式的Encoding和Decoding。

Prerequisites

Reactor Core最低支持Java 8。
它依赖org.reactivestreams:reactive-streams:1.0.2。

Android支持:

  • Reactor 3没有正式支持Android(RxJava 2支持)
  • 在Android SDK 26以上可以工作得很好

Introduction to Reactive Programming

Reactor是响应式编程范式的一个实现,可以概括为:
响应式编程是关于数据流和变化传播(the propagation of change)的异步编程范式。这意味着可以通过采用的编程语言轻松地表达静态(比如数组)或者动态(比如事件发送器)的数据流。
Reactive_programming

Microsoft最先在.NET ecosystem增加了Reactive Extensions(Rx)库。然后,RxJava在JVM上实现了响应式编程。后来,通过Reactive Streams实现了Java上的标准化-Flow类定义的接口集和交互规则集成到了Java 9内。
响应式编程范式通常在面向对象的语言中出现,是Observer设计模式的扩展。比较一下响应式流和Iterator设计模式,一个主要不同点是,Iterator是pull-based的,而响应式流是push-based。
使用一个迭代器是一种命令式的编程模式,尽管访问值的方法完全是Iterable的责任。开发人员可以选择何时访问序列中的next()项。
而响应式流,是发布-订阅模式的。发布者提醒订阅者来了新值,这种push是响应式的关键。除了推送值,还以明确定义的方式,涵盖错误处理和完成。通过调用onNext,发布者将新值推送给订阅者。也可以通过调用onError发送一个错误信号,或者通过onComplete完成。错误和完成都会终止序列,可以概括为:

onNext x 0..N [onError | onComplete]

这种方法非常灵活,它支持没有值、一个值和n个值(包括无限的值序列,比如时钟的连续滴答)。

但是,为什么需要一个异步的响应式库呢?

Blocking Can Be Wasteful

现代程序可以覆盖大量并发用户,虽然硬件性能在持续提升,可软件性能还是一个关键问题。
有两种办法提高程序性能:

  • parallelize:采用更多线程和更多硬件资源
  • seek more efficiency:寻求当前资源的更高效率

一般来说,Java程序都是阻塞式的。容易达到性能瓶颈,就需要更多线程,运行类似的阻塞代码。这样做,很快就会出现争用和并发问题。
更糟糕的是,阻塞浪费资源。如果仔细观察,一旦程序涉及延迟(特别是I/O,比如数据库操作和网络调用),资源就会被浪费-因为线程处于空闲或者等待数据的状态。

Asynchronicity to the Rescue?

也可以编写异步的、非阻塞的代码,使用相同的底层资源切换到其他活动任务,等异步处理执行完成再切换回来。
在JVM内,怎么写异步代码呢?

  • Callbacks:异步方法没有返回值,但是需要额外的回调参数(lambda或者匿名类),结果有效时就调用该参数。比如Swing中的EventListener
  • Futures:异步方法立即返回Future。异步过程计算T的值,Future对象包装了对值的访问。该值不会立即有效,值有效以后才可以拉取(poll)。比如运行Callable任务的ExecutorService使用Future对象

这两种方法都有局限性。
Callbacks很难组合到一起。阅读和维护起来也很困难。

From Imperative to Reactive Programming

诸如Reactor这样的响应式库不但解决上述缺点,还关注其他方面:

  • 组合性和可读性
  • 数据作为流(flow),有丰富的operators
  • subscribe前什么都没发生
  • Backpressure,消费者向生产者发送明确的信号,表明生产得太快了
  • 与并发无关的高级抽象

Composability and Readability

composability是指有能力编排多个异步任务,前一个任务的结果就是后续任务的输入,或者使用fork-join执行几个任务,也可以重用任务,把它作为更高级系统的组件。
编排任务的能力与代码的可读性和可维护性紧密相关。随着异步过程层级的数量和复杂性的增加,编写和阅读代码都变得越来越难。正如我们所看到的,回调很简单,但它的一个主要缺点是,对于复杂的过程,你需要在回调中执行回调,他们嵌套在一起(Callback Hell)。
Reactor提供了丰富的组合选项,代码反应了抽象过程的组织,全都位于同一级(嵌套最小化)。

The Assembly Line Analogy

你可以想象为,响应式程序里的数据在装配线上移动。Reactor既是传送带,又是工作站。原材料从源注入(Publisher),最终的成品推送给消费者(Subscriber)。
原材料经历各种转换和其他中间步骤,或者是大型装配线上的一部分和其他部件聚合到一起。如果在某一点出现了故障或者堵塞(也许花费了太长时间),受影响的工作站可以向上游信号以限制原材料的流动。

Operators

Reactor中,operators就是装配线类比中的工作站。每个operator都会向Publisher添加行为,并把前一步的Publisher包装成新的实例。整个链就这样形成了,数据从第一个Publisher沿着链向后移动,由每个link转发。最终,Subscriber完成了该过程。记住,在Subscriber订阅Publisher前,什么都没发生。
Reactive Streams规范根本没有指定任何operators,Reactor的最佳附加值就是添加了丰富的operators。他们涉及很多方面,从简单的转换、过滤到复杂的编排和错误处理。

Nothing Happens Until You subscribe()

Reactor中,当你写一个Publisher链,默认情况下,数据不会启动。你要增加一个异步处理的抽象描述(帮助重用和组合)。
通过订阅,把Publisher绑定到Subscriber,从而出发整个链中的数据流。在内部,Subscriber发送一个request信号,向上游传递,直到Publisher。

Backpressure

backpressure也是通过向上游传递信号实现的,还是用装配线做类比,如果工作站处理得比上游慢就发送一个反馈信号。
Reactive Streams规范的定义非常接近类比:subscriber可以在unbounded模式工作,让源以最快的速度推送数据;或者使用request机制,向源发信号,它现在可以处理最多n条数据。
中间operators也可以改变request。比如buffer operator,可以把数据分组。还有些operators实现了prefetching策略,这就避免了request(1)往返,如果在请求之前就生成元素不太昂贵,这样处理是划算的。
这样,把push模式变成了push-pull,如果有数据,下游可以从上游pull数据。如果没有数据,就等数据准备好以后push给下游。

Hot vs Cold

有两大类反应式序列hot和cold。主要区别是响应式流如何应答订阅:

  • Cold:为每个Subscriber都生成新的序列,包括数据源。比如,如果源包装了一个HTTP调用,就为每个订阅生成一个新的HTTP请求
  • Hot:对于每个Subscriber,不会重新开始。相反,迟到的订阅者只能接收到订阅之后发射的数据。注意,一些hot响应式流可以缓存或者重放历史(甚至全部历史)。hot的序列甚至可以在没有订阅者时也发射数据

Reactor Core Features

Reactor提供了可组合的响应式类型,他们(Flux和Mono)实现了Publisher,还提供了丰富的operators。Flux代表0…N个元素,Mono代表(0…1)。
比如,HTTP请求只有一个响应,所以应该不会做count运算。所以,使用Mono代表一次HTTP请求的结果会更好。
改变最大基数的Operators会切换相关类型。比如,Flux才有count运算,但是它返回Mono。

Flux, an Asynchronous Sequence of 0-N Items

Flux

Flux是一个标准的Publisher,可以由一个completion信号或者error终止。三种类型的信号转换为对下游Subscriber的onNext、onComplete或者onError方法的调用。
所有的事件,包括terminating,都是可选的。如果没有onNext事件但是有onComplete代表一个empty有限序列;而删除了onComplete,就变成一个无限的空序列(没什么用,除非要测试cancellation)。
无限序列不一定是空的,比如,Flux.interval(Duration)生产的Flux就是无限的,根据时钟发出滴答声。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值