學習響應式編程 Reactor (1) - 響應式編程

響應式編程

命令式編程(Imperative Programing),是一種描述計算機所需作出的行爲的編程範式。詳細的命令機器怎麼(How)去處理以達到想要的結果(What)。
聲明式編程(Declarative Programing),是一種編程範式,與命令式編程相對立。它描述目標的性質,讓計算機明白目標,而非流程。只告訴機器想要的結果(What),機器本身摸索過程(How)。html

響應式編程(Reactive Programing)是一種關注數據流(data streams)和變化傳遞(propagation of charge)的異步編程方式,它屬於聲明式編程範式。java

上面的文字理論性比較強,說的直白一點:react

數據流就像一條河:它能夠被觀測,被過濾,被操做(和 Java Stream 一致),或者爲新的消費者與另一條流合併爲一條新的流。
響應式編程的一個關鍵概念是事件。事件能夠被等待,能夠觸發過程,也能夠除法其它事件。事件是惟一以合適的方式將咱們的現實世界映射到咱們的軟件中:若是屋裏太熱了,咱們就打開一扇窗。
一樣的,當咱們的天氣 app 從服務器端獲取到新的天氣數據後,咱們須要更新 app 上展現天氣的 UI ;汽車上的車道偏移系統探測到車輛偏移了正常路線就會提醒駕駛者糾正;這些就是響應事件。git

響應式編程能夠理解爲面向對象中觀察者模式(Observer Design Pattern)的一種擴展,它也與迭代器模式(Iterator Design Pattern)
有相同之處,響應式流(reactive streams)其中也有 Iterable - Iterator 這樣的對應關係,主要的區別在於 Iterator 是基於拉取(pull)
方式的,而響應式流是基於推送(push)方式的。github

Iterator 迭代器(模式)也是命令式編程方式,即便訪問值的方法使用的是 iterable 方法,何時獲取 next 是由開發者決定的。在響應式流中,相對應的角色是發佈者(publisher) - 訂閱者(Subscriber),當有新值到來的時候,是由發佈者通知訂閱者,這種典型的推送方式是響應式流的關鍵,同時對推送來的數據的操做是聲明式的表達,而不是命令式的,開發者經過描述控制流程來定義對數據流的處理邏輯。數據庫

除了數據推送,響應式流還提供了數據流完成的信號和發生錯誤的信號。一個發佈者能夠隨時向訂閱者推送數據(onNext),同時也能夠推送錯誤(onError)和完成信號(onComplete),錯誤和完成信號都將終止響應流。編程

說了這麼多理論性描述,那麼響應式編程到底牛叉在哪裏呢?後端

阻塞是資源浪費

以現實中的雙11秒殺爲例,當大量用戶同時在0點發起搶購某個商品時,假設在不作任何限流、架構優化等的狀況下,大量的請求將同時進入到後端,以tomcat容器爲例,tomcat將爲用戶建立大量的線程(受線程池控制)來響應用戶請求,後端的代碼收到請求後,須要執行以下邏輯:判斷用戶的下單請求是否合理有效,判斷用戶是否參與過當前商品的秒殺,判斷當前商品庫存是否充足,若是庫存充足,執行下單鎖庫存,隨着併發數的加大,這一套代碼邏輯執行下來將會花費很長時間,同時tomcat以前的線程一直阻塞着,等待servlet的結果來最終響應給用戶。tomcat

現代應用面對大量的併發用戶,即便硬件的處理能力高速發展,軟件性能還是關鍵因素。安全

廣義來講,有兩種方式來提升軟件性能:

  1. 並行化,使用更多的線程和硬件資源;
  2. 優化現有(代碼)資源,提升執行效率。

一般,開發者使用阻塞式編寫代碼,在出現性能瓶頸後,咱們能夠增長處理線程,線程中一樣是阻塞的代碼。可是這種使用資源的方式會面臨資源的競爭和併發問題。同時,阻塞會浪費資源。具體來講,當一個程序面臨延遲(一般是 I/O 方面,好比數據庫讀寫和網絡請求),所在線程進入 idle 狀態等待返回,從而浪費資源。因此並行化並不是解決問題的最佳方式,它是挖掘硬件潛力的方式,可是帶來了複雜性,並形成了對資源的浪費。

異步能夠解決問題嘛?

第 2 個思路,提升執行效率,經過編寫異步非阻塞的代碼,任務發起異步調用後,執行過程會切換到另外一個(使用一樣底層資源)活躍任務,等待異步任務返回結果後再去處理,這樣能夠解決資源的浪費問題。

Java 提供了2種方式實現異步代碼:

  1. 回調:異步方法沒有返回值,而是採用一個 callback 做爲參數,當有結果後,回調這個 callback。常見的例子,好比 Swing 中
    的 EventListener。
  2. Future:異步方法當即返回一個 Future ,Future 的結果不是立馬能夠拿到,須要等待異步任務執行完成後,纔可使用。

可是這兩個方法都有他們的侷限性:

  1. 若是在回調中嵌套回調時,多層嵌套的回調將致使代碼難以理解和維護,即所謂的嵌套地獄。
  2. Future 比回調要好一點,即便在 Java 8 中引入了 CompletableFuture,他對於多個處理的組合仍不友好。編排多個 Future 是可行的,
    但卻不易。此外,Future 還有一個問題,當對 Future 對象調用 get() 方法時,仍然會致使阻塞,而且缺少對多個值以及更進一步對錯誤
    的處理。

從命令式編程到響應式編程

基於上面提到的問題,開發牛人們提出了響應式流解決方案。在響應式編程方面,微軟是先行者,他們率先在 .NET 中建立了響應式擴展庫(Reactive Extensions Library, Rx)。接着,RxJava 在 JVM 上實現了響應式編程。後來,在 JVM 平臺出現了一套響應式編程規範,它定義了一系列編程接口和交互規範,並整合到了 Java 9 中。

除了解決上述問題,響應式編程庫還額外關注以下幾個方面:

  1. 可編排性(Composability)和可讀性(Readability)
  2. 提供豐富的操做符(operators)來處理形如流的數據
  3. 在訂閱(Subscribe)以前什麼都不發生
  4. 背壓(BackPressure)支持,簡單來講,訂閱者可以反向告知發佈者生產內容速度的能力
  5. 高層次的抽象,從而達到併發無關的效果

RxJava 和 Reactor

RxJava

RxJava 是 Reactive Extensions 的 Java VM 實現,它用於經過使用可觀察的序列來組成異步和基於事件的程序。

它擴展了觀察者模式以支持數據/事件序列,並添加了運算符,使您能夠聲明性地將序列組合在一塊兒,同時消除了對諸如多線程,同步,線程安全和併發數據結構之類的問題的擔心。

RxJava 是 Java 界響應式編程的先行者,由於是先有的 RxJava,才後有的 Java 版本的響應式編程規範,同時該規範定義時參考了 RxJava 的許多定義,RxJava 的早期版本最低支持 Java 6,官方版本直至 Java 9 中才被支持。

RxJava 最新版本 3.x,最低須要 Java 8+,官方請看 https://github.com/ReactiveX/RxJava

Reactor

Reactor 是一個用於 JVM 的徹底非阻塞的響應式編程框架,具有高效的需求管理(即對 「背壓(backpressure)」的控制)能力。它與 Java 8 函數式 API 直接集成,好比 CompletableFuture, Stream, 以及 Duration。它提供了異步序列 API Flux(用於[N]個元素)和 Mono(用於 [0|1]個元素),並徹底遵循和實現了「響應式擴展規範」(Reactive Extensions Specification)。

Reactor 的 reactor-ipc 組件還支持非阻塞的進程間通訊(inter-process communication, IPC)。 Reactor IPC 爲 HTTP(包括 Websocket)、TCP 和 UDP 提供了支持背壓的網絡引擎,從而適用於微服務架構。而且完整支持響應式編解碼(reactive encoding and decoding)。

Reactor 是第四代響應式框架,跟 RxJava 2 有些類似。Reactor 項目由 Pivotal 啓動,以響應式流規範、Java8 和 ReactiveX 術語表爲基礎。它的設計是 Reactor 2(上一個主要版本)和 RxJava 核心貢獻者共同努力的結果。

從設計概念方面來看,RxJava 有點相似 Java 8 Steams API。而 Reactor 看起來有點像 RxJava,不過這決不僅是個巧合。這樣的設計是爲了可以給複雜的異步邏輯提供一套原生的具備 Rx 操做風格的響應式流 API。因此說 Reactor 紮根於響應式流,同時在 API 方面儘量地與 RxJava 靠攏。

Reactor 最新版本3.x,最低須要 Java 8+,官方請看 https://github.com/reactor/reactor-core

Java Stream Vs RxJava Vs Reactor

咱們在前傳中首先學習了Java Stream,經過上面筆記的介紹,發現 Java Stream 在不少方面與響應式編程方面類似,那麼他們到底有哪些區別呢,來看徐靖峯在【八個層面比較 Java 8, RxJava, Reactor】中的下面這張圖:

因爲上述文章已經講解的很好了,請你們跳轉過去學習一下。

總結

RxJava 在 Android 開發界可算是如火如荼,經過事件的響應配合界面的操做可謂如魚得水。Reactor 直至 Spring 5 中引入了 Reactive Stream 及 Spring WebFlux 才進入了個人視線,RxJava 的學習內容基本遍地都是了,而 Reactor 的內容卻少之又少,這也是本片筆記的由來。

響應式編程的理論部分,總算是介紹完了。理論知識一直是個人弱勢,上面的大部份內容都是源自 Reactor 的官方文檔及下方各個參考文檔,感興趣的朋友可到對應的文章學習瞭解下。

今天的內容就講到這裏,咱們下篇開始 Reactor 的學習。

參考

  1. 響應式規範
  2. Reactor 3 中文指南
  3. 這多是最好的RxJava 2.x 教程(完結版)
  4. 從新理解響應式編程
  5. 八個層面比較 Java 8, RxJava, Reactor
相關文章
相關標籤/搜索