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

来源:https://www.cnblogs.com/todev/archive/2020/06/17/13154006.html
-Advertisement-
Play Games

響應式編程 命令式編程(Imperative Programing),是一種描述電腦所需做出的行為的編程範式。詳細的命令機器怎麼(How)去處理以達到想要的結果(What)。 聲明式編程(Declarative Programing),是一種編程範式,與命令式編程相對立。它描述目標的性質,讓電腦 ...


響應式編程

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

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

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

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

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

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

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

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

阻塞是資源浪費

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

現代應用面對大量的併發用戶,即使硬體的處理能力高速發展,軟體性能仍是關鍵因素。

廣義來說,有兩種方式來提高軟體性能:

  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

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前言 本文的文字及圖片來源於網路,僅供學習、交流使用,不具有任何商業用途,版權歸原作者所有,如有問題請及時聯繫我們以作處理。 Matplotlib 是一個 Python 的 2D繪圖庫(當然也可以畫三維形式的圖形哦),它以各種硬拷貝格式和跨平臺的互動式環境生成出版質量級別的圖形 。通過 Matplo ...
  • Collection是一種關於集合的類 在Collection類中共有的方法有: add(E e):添加 remove(E e):指定元素刪除 contains(E e):指定元素是否存在 isEmpty():判斷是否為空 size():返回元素個數 to Array():元素變成數組 clean( ...
  • 案例故事: 大部分帶彩色屏幕的終端設備,不管是手機,車機,電視等等,都需要涉及圖片的顯示, 作為一名專業的多媒體測試人員,我們需要一堆的規範化標準的的圖片測試文件, 但是發現圖片資源名字命名的很隨意比如:IMG_20200325_161111.jpg, 以上命名不能看出圖片文件的具體圖片編碼格式,分 ...
  • app拿soul為例子 一.環境配置 #模擬器的frida服務為86 #frida-server-12.9.8-android-x86 adb push frida-server-12.9.8-android-x86 /data/local/tmp/ adb shell ./frida-server ...
  • 1.多態(polymorphism) 多態指的是同一個方法調用,由於對象不用可能會有不用的行為。現實生活中,同一個方法,具體實現會完全不同。 比如: 動物會叫,狗就是汪汪汪,貓就是喵喵喵 多態的要點: 1.多態是方法的多態,不是屬性的多態(多態與屬性無關) 2.多態的存在要有三個必要條件:繼承,方法 ...
  • 前言 遞歸,是一個非常重要的概念,也是面試中非常喜歡考的。因為它不但能考察一個程式員的演算法功底,還能很好的考察對時間空間複雜度的理解和分析。 本文只講一題,也是幾乎所有演算法書講遞歸的第一題,但力爭講出花來,在這裡分享四點不一樣的角度,讓你有不同的收穫。 時空複雜度的詳細分析 識別並簡化遞歸過程中的重 ...
  • ...
  • Python學習之路——pycharm的第一個項目 簡介: 上文中已經介紹如何安裝Pycharm已經環境變數的配置。現在軟體已經安裝成功,現在就開始動手做第一個Python項目。第一個“Hello World”項目。 第一步:打開Pycharm軟體 1.雙擊,桌面圖標,運行軟體,進入軟體後,點擊“C ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...