自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

一文讀懂響應式編程到底是什么?

開發(fā) 前端
為了應對高并發(fā)服務器端開發(fā)場景,在2009 年,微軟提出了一個更優(yōu)雅地實現(xiàn)異步編程的方式—— Reactive Programming ,我們稱之為響應式編程。

 最近幾年,隨著Go、Node 等新語言、新技術的出現(xiàn),Java 作為服務器端開發(fā)語言老大的地位受到了不小的挑戰(zhàn)。雖然Java 的市場地位在短時間內(nèi)并不會發(fā)生改變,但Java 社區(qū)還是將挑戰(zhàn)視為機遇,并努力、不斷地提高自身應對高并發(fā)服務器端開發(fā)場景的能力。

為了應對高并發(fā)服務器端開發(fā)場景,在2009 年,微軟提出了一個更優(yōu)雅地實現(xiàn)異步編程的方式—— Reactive Programming ,我們稱之為響應式編程

隨后,各語言很快跟進,都擁有了屬于自己的響應式編程實現(xiàn)。比如,JavaScript 語言就在ES6 中通過Promise 機制引入了類似的異步編程方式。同時,Java 社區(qū)也在快速發(fā)展,Netflix 和LightBend 公司提供了RxJava 和Akka Stream 等技術,使得Java 平臺也有了能夠實現(xiàn)響應式編程的框架。

當下,我們通過Mina 和Netty 這樣的NIO 框架其實就能完成高并發(fā)下的服務器端開發(fā)任務,但這樣的技術只掌握在少數(shù)高級開發(fā)人員手中,因為它們難度較大,并不適合大部分普通開發(fā)者。

雖然目前已經(jīng)有不少公司在實踐響應式編程,但整體來說,其應用范圍依舊不大。出現(xiàn)這種情況的原因在于當下缺少簡單、易用的技術,這些技術需要能使響應式編程更加普及,并做到如同Spring MVC 一樣結合Spring 提供的服務對各種技術進行整合。

在2017 年9 月28 日,Spring 5 正式發(fā)布。Spring 5 發(fā)布最大的意義在于,它將響應式編程技術的普及向前推進了一大步。而同時,作為在背后支持Spring 5 響應式編程的框架Spring Reactor,也進入了里程碑式的3.1.0 版本。

響應式編程到底是什么?

在現(xiàn)實生活中,當我們聽到有人喊我們名字的時候,會對其進行響應,也就是說,我們是基于事件驅動模式來進行編程的。所以這個過程其實就是下發(fā)產(chǎn)生的事件,然后我們作為消費者對下發(fā)事件進行一系列的消費。

從這個角度來說,對整個代碼的設計應該是針對消費者來進行的。比如,看電影,有些畫面我們不想看,那就閉上眼睛;有些聲音不想聽,那就捂上耳朵。其實這就是對消費者的增強包裝,我們把復雜的邏輯拆分開,然后將其分割成一個個小任務進行封裝,于是就有了諸如filter、map、skip、limit 等操作。

01

并發(fā)與并行的關系

可以說,并發(fā)很好地利用了CPU 時間片的特性,也就是操作系統(tǒng)選擇并運行一個任務,接著在下一個時間片內(nèi)運行另一個任務,并把前一個任務設置成等待狀態(tài)。其實并發(fā)并不意味著并行。

具體列舉下面幾種情況。

① 有時候,多線程執(zhí)行會提高應用程序的性能,而有時候反而會降低應用程序的性能。這在 JDK 中Stream API 的使用上體現(xiàn)得很明顯,如果任務量很小,而我們又使用了并行流,反而降低了應用程序的性能。

② 在多線程編程中,可能會同時開啟或者關閉多個線程,這樣會產(chǎn)生很大的性能開銷, 也降低了應用程序的性能。

③ 當線程同時處于等待I/O 的過程中時,并發(fā)可能會阻塞CPU 資源,其后果不僅是用戶長時間等待,而且會浪費CPU 的計算資源。

④ 如果幾個線程共享了一個數(shù)據(jù),情況就會變得有些復雜。我們需要考慮數(shù)據(jù)在各個線程中的狀態(tài)是否一致。為了達到數(shù)據(jù)一致的目的,很可能會使用synchronized 或者lock 相關操作。

現(xiàn)在,你對并發(fā)有一定的了解了吧。并發(fā)很好,但并不一定會實現(xiàn)并行。并行是在多核CPU 上同一時間運行多個任務或者一個任務分為多塊同時執(zhí)行(如ForkJoin)。單核CPU 的話,就不要考慮并行了。

補充一點,實際上多線程就意味著并發(fā),但是并行只發(fā)生在這些線程在同一時間調(diào)度、分配到不同CPU 上執(zhí)行的情況下。也就是說,并行是并發(fā)的一種特定形式。一個任務里往往會產(chǎn)生很多元素,這些元素在不參與操作的情況下大都只能處于當前線程中,這時我們可以對其進行ForkJoin,但這對很多程序員來講有時候很不好操作、控制,上手難度有些大。這時如果用響應式編程,就可以簡單地通過所提供的調(diào)度API 輕松做到事件元素的下發(fā)、分配,其內(nèi)部會將每個元素包裝成一個任務并提交到線程池中,我們可以根據(jù)任務是計算型的還是I/O 型的來選擇相應的線程池。

在這里,需要強調(diào)一下,線程只是一個對象,不要把它想象成CPU 中的某一個執(zhí)行核心,這是很多人都在犯的錯,CPU 時間片會切換執(zhí)行這些線程。

02

如何理解響應式編程中的背壓

背壓,由Back Pressure 翻譯得到,從英文字面意思講,稱之為回壓可能更合適。首先解釋一下回壓,它就好比用吸管喝飲料,將吸管內(nèi)的氣體吸掉,吸管內(nèi)形成低壓,進而形成飲料至吸管方向的吸力,此吸力將飲料吸進人嘴里。我們常說人往高處走,水往低處流,水之所以會出現(xiàn)這種現(xiàn)象,其實是重力所致。而現(xiàn)在吸管下方的水上升進入人的口中,說明出現(xiàn)了下游指向上游的逆向壓力,而且這個逆向壓力大于重力,可以稱這種情況為背壓。這是一個很直觀的詞,向后的、往回的壓力——Back Pressure。

放在程序中,也就是在數(shù)據(jù)流從上游源生產(chǎn)者向下游消費者傳輸?shù)倪^程中,若上游源生產(chǎn)速度大于下游消費者消費速度,那么可以將下游想象成一個容器,它處理不了這些數(shù)據(jù),然后數(shù)據(jù)就會從容器中溢出,也就出現(xiàn)了類似于吸管例子中的情況?,F(xiàn)在,我們要做的事情就是為這個場景提供解決方案,該解決方案被稱為背壓機制。

為了更好地解決背壓帶來的問題,我們回到現(xiàn)實中看一個事物——大壩。在發(fā)洪水期間,下游沒辦法一下子消耗那么多水,大壩此時的作用就是攔截洪水,并根據(jù)下游的消耗情況酌情排放,也就是說,背壓機制應該放在連接元素生產(chǎn)者和消費者的地方,即它是生產(chǎn)者和消費者的銜接者。然后,根據(jù)上面對大壩的描述,背壓機制應該具有承載元素的能力,也就是它必須是一個容器,而且其存儲與下發(fā)的元素應該有先后順序,那么這里使用隊列是最適合的了。背壓機制僅起承載作用是不夠的,正因為上游進行了承壓,所以下游可以按需請求元素,也可以在中間根據(jù)實際情況進行限流,以此上下游共同實現(xiàn)了背壓機制。在本書后續(xù)內(nèi)容及相關的配套視頻中會介紹背壓的相關API。

03

Reactor 與RxJava 的對比

關于響應式編程,我寫的《Java 編程方法論:響應式RxJava 與代碼設計實戰(zhàn)》一書已經(jīng)出版,那么Reactor 與RxJava 又有什么區(qū)別呢?首先我要明確地告訴你,如果你使用的是Java 8+,那么推薦使用Reactor 3,而如果你使用的還是Java 6+或函數(shù)需要做異常檢查,那么推薦使用RxJava 2。

從上圖可以看到,RxJava 2 和Reactor 共用了一套接口API 標準Reactive Streams Commons,這也說明它們的最終目的是一致的,而且API 具有通用性,這樣也降低了學習成本。

下面再來回顧一下RxJava。

迄今為止,RxJava 發(fā)行版主要分三大版本RxJava 3、RxJava 2 和RxJava 1。與RxJava 1 不同,RxJava 3、RxJava 2 直接通過新添加的Flowable 類型來實現(xiàn)Publisher 的接口定義(RxJava 3 與RxJava 2 并沒有太多區(qū)別,故這里只介紹RxJava 2)。同時,RxJava 2 依然保留了RxJava 1 中的Observable、Completable 和Single,并引入了支持Optional 的Single 升級版——Maybe 類型。RxJava 1 中的Observable 不支持RxJava 2 中的背壓機制,背壓機制是Flowable 的專有功能,不過Observable 內(nèi)部提供了可轉換API。需要注意的是,Observable 實現(xiàn)的是RxJava 2 中自定義的ObservableSource 接口。

在Reactor 中,可以發(fā)現(xiàn)Mono 和Flux 兩種類型都實現(xiàn)了Publisher 接口,同時兩者皆實現(xiàn)了背壓機制。Flux 可以對標RxJava 2 中的Flowable 類型,而Mono 可以被理解為RxJava 2 中對Single 的背壓加強版。后續(xù),我們會進行更深入的講解。

同樣,下面再來了解一下Reactor 與RxJava 的不同之處。

  • 為了兼容 Java 1.6+ ,RxJava 不得不自行定義了一些函數(shù)式接口,可以參考io.reactivex.functions 下的接口定義。而Reactor 3 則是基于JDK 中提供的java.util.function 來設計實現(xiàn)的。
  • 可以很輕松地從java.util.stream.Stream 轉換為Flux,也可以很輕松地由后者轉換為前者。
  • 同樣,可以很輕松地實現(xiàn)CompletableFuture 與Mono 之間的互相轉換,也可以輕松而安全地基于Optional 類型的元素創(chuàng)建Mono。
  • Reactor 3 可以更好地服務于Spring Framework 5,也更適應最新版本的JDK。

最后,我們再簡單介紹一下上圖中的幾個部分。

Core 是我們主要研究的庫,是Reactor 的核心實現(xiàn)庫。其作用與RxJava 2 的核心實現(xiàn)的作用是一樣的,本書主要介紹reactor-core 模塊。

IPC 可以認為它是針對encode、decode、send(unicast、multicast 或request/response )及服務連接而設計的支持背壓的組件。IPC 支持Kafka、Netty 及Aeron。

Addons 其中包括reactor-adapter、reactor-logback 和reactor-extra。reactor-adapter 可以說是連接RxJava 1/2 中Observable、Completable、Flowable、Single、Maybe、Scheduler 的橋梁,可以方便地與Reactor 3 進行轉換操作。同樣,這個庫對于Swing/SWT Scheduler、Akka Scheduler 也做了針對性適配。reactor-logback 用于支持Reactor Core 異步處理Logback 方面的功能。reactor-extra 為數(shù)字類型的Flux 源提供了很多數(shù)學運算的操作。

Reactive Streams Commons 是RxJava 2 和Reactor 共用的一套接口API 標準。

責任編輯:張燕妮 來源: 今日頭條
相關推薦

2021-01-18 13:05:52

Serverless Serverfull FaaS

2022-07-15 08:16:56

Stream函數(shù)式編程

2019-12-04 13:50:07

CookieSessionToken

2023-06-26 16:51:49

數(shù)字孿生數(shù)字技術

2016-10-25 14:35:05

分布式系統(tǒng) 存儲

2023-09-18 07:23:25

ESQS散片

2021-10-18 14:30:55

物聯(lián)網(wǎng)IOT

2019-06-28 08:31:01

微內(nèi)核安卓系統(tǒng)

2019-09-04 19:29:14

云計算混合云資源

2023-12-22 19:59:15

2021-08-04 16:06:45

DataOps智領云

2023-05-11 15:24:12

2018-05-29 16:20:55

區(qū)塊鏈比特幣

2020-10-14 06:22:14

UWB技術感知

2010-11-01 01:25:36

Windows NT

2020-09-22 08:22:28

快充

2020-09-27 06:53:57

MavenCDNwrapper

2021-08-31 07:02:34

數(shù)據(jù)響應Vue偵測數(shù)據(jù)變化

2018-09-28 14:06:25

前端緩存后端

2025-04-03 10:56:47

點贊
收藏

51CTO技術棧公眾號