?譯者 | 陳峻
審校 | 孫淑娟
早在上世紀(jì)60年代, IT領(lǐng)域就首次出現(xiàn)了“響應(yīng)式編程(reactive programming,Rx)”一詞。它在??維基百科中的定義??為:在計(jì)算機(jī)中,處理數(shù)據(jù)流和傳遞變更的一種聲明式編程方法。這種范式允許用戶輕松地指定靜態(tài)(如,數(shù)組)或動(dòng)態(tài)(如,事件發(fā)射器)數(shù)據(jù)流,以及表明相關(guān)執(zhí)行模型內(nèi)部存在的、已推斷出的依賴關(guān)系,進(jìn)而允許自動(dòng)傳遞數(shù)據(jù)流的變更。在Rx編程中,各種數(shù)據(jù)流由同一個(gè)組件生成。各個(gè)Rx庫(kù)提供了底層的結(jié)構(gòu),并將這些變更傳遞給已注冊(cè)的、可接受此類(lèi)數(shù)據(jù)變更的其他組件處。
關(guān)于響應(yīng)式編程
總地說(shuō)來(lái),響應(yīng)式編程是各種observable、observer和scheduler的結(jié)合。下面,我們將對(duì)這些術(shù)語(yǔ)進(jìn)行深入解釋。
Observable
數(shù)據(jù)可以通過(guò)一個(gè)線程被傳輸?shù)搅硪粋€(gè)線程,并存儲(chǔ)在observable中。簡(jiǎn)單地說(shuō),observable是一種數(shù)據(jù)流。根據(jù)具體設(shè)置的不同,數(shù)據(jù)可以被定期發(fā)送,或者在其生命周期內(nèi)僅發(fā)送一次。
一些操作符(operator)可以幫助observer(我們會(huì)在下一部分詳細(xì)介紹到)發(fā)出特定的數(shù)據(jù),以響應(yīng)各種事件。您可以暫且把observable視為提供者(supplier)。它們不但會(huì)處理數(shù)據(jù),而且能夠?qū)⑵浒l(fā)送到系統(tǒng)的其余部分。
Observers
Observer可以被理解為是消費(fèi)者(consumer)。它們使用之前已注冊(cè)的observable,發(fā)送數(shù)據(jù)流。
Schedulers
簡(jiǎn)而言之,在異步編程中,它們輕松地實(shí)現(xiàn)了線程管理。scheduler能夠指示observable和observer使用哪些線程。
什么時(shí)候適合使用響應(yīng)式編程?
通常,我們?cè)谔幚懋惒綌?shù)據(jù)流時(shí),響應(yīng)式編程是一種流行的選擇。畢竟用例中的微小變化也可能成為我們決策的決定性因素。以下便是一些在現(xiàn)實(shí)世界中使用響應(yīng)式編程的示例:
使用響應(yīng)式編程開(kāi)發(fā)移動(dòng)應(yīng)用程序
由于移動(dòng)設(shè)備在性能上不足以處理繁重的任務(wù),因此我們經(jīng)常需要在執(zhí)行期間或任務(wù)之后,根據(jù)后臺(tái)線程來(lái)更新主線程上的用戶界面。對(duì)此,我們需要在服務(wù)器上執(zhí)行繁重的工作和復(fù)雜的計(jì)算??梢?jiàn),對(duì)于此類(lèi)網(wǎng)絡(luò)通訊活動(dòng)的異步工作需求,響應(yīng)式編程正好可以發(fā)揮作用。
在Netflix API中與RxJava一起使用響應(yīng)式編程
為了減少網(wǎng)絡(luò)中的常規(guī)交互,我們需要使用RxJava服務(wù)器端的并發(fā)機(jī)制,在Netflix API中進(jìn)行響應(yīng)式編程。由于來(lái)自某個(gè)設(shè)備的每一個(gè)網(wǎng)絡(luò)請(qǐng)求,都會(huì)自動(dòng)與其他網(wǎng)絡(luò)請(qǐng)求并行處理,因此如果服務(wù)器端無(wú)法支持并發(fā)執(zhí)行的話,那么單個(gè)“重”的客戶端請(qǐng)求,很可能都不如幾個(gè)“輕”的客戶端請(qǐng)求的被處理速度。而且,即使我們已將網(wǎng)絡(luò)延遲考慮在內(nèi),如果一個(gè)已壓縮的“重”請(qǐng)求服務(wù)器端,在處理中沒(méi)有達(dá)到相同程度的并行處理,那么它就可能會(huì)比多個(gè)“輕”的請(qǐng)求要慢得多。
外部調(diào)用服務(wù)
由于如今許多后端服務(wù)都是RESTful類(lèi)型(即,它們使用的是HTTP),因此底層協(xié)議可能會(huì)造成阻塞,以及出現(xiàn)同步調(diào)用外部服務(wù)的情況。在進(jìn)行服務(wù)開(kāi)發(fā)的時(shí)候,我們不但需要經(jīng)常聯(lián)絡(luò)和調(diào)用其他的服務(wù),而且要根據(jù)第一次調(diào)用的結(jié)果,按需調(diào)用額外更多的服務(wù)。因此,在面對(duì)眾多I/O時(shí),我們需要在發(fā)出下一個(gè)請(qǐng)求之前,等待前一個(gè)調(diào)用的完成。而這往往會(huì)導(dǎo)致我們的客戶,因?yàn)閱适Х?wù)響應(yīng)等待的耐心,而放棄后續(xù)的使用。
因此,我們有必要優(yōu)化外部服務(wù)的調(diào)用,特別是那些針對(duì)跨不同調(diào)用之間復(fù)雜依賴關(guān)系的編排。響應(yīng)式編程能夠保障此類(lèi)活動(dòng)的背后,在邏輯上的“可組合性”,以便調(diào)用服務(wù)的開(kāi)發(fā)人員能夠更容易地編寫(xiě)相關(guān)的代碼。
高并發(fā)消息的消費(fèi)者
一種典型的企業(yè)用例往往發(fā)生在有大量并發(fā)消息處理的消費(fèi)者處,尤其是在那些高度同步的情況下。而響應(yīng)式框架的優(yōu)勢(shì)就在于:通過(guò)測(cè)量微基準(zhǔn)(microbenchmark),實(shí)現(xiàn)了每秒都能夠在JVM上處理大量的消息。
整合響應(yīng)式編程
在線游戲、社交媒體和多人聊天室,都是持續(xù)使用音頻和視頻的應(yīng)用程序(主要被用于流媒體)。而當(dāng)涉及到特定類(lèi)型的高負(fù)載、或多用戶應(yīng)用時(shí),響應(yīng)式編程顯然是一個(gè)優(yōu)雅的解決方案。不過(guò),響應(yīng)式技術(shù)的引入也可能會(huì)增加不必要的復(fù)雜性,甚至?xí)o應(yīng)用程序的性能帶來(lái)影響。因此,我們需要通過(guò)如下三個(gè)簡(jiǎn)單步驟,合理地將響應(yīng)式程序集成到目標(biāo)應(yīng)用中:
第1步:創(chuàng)建一個(gè)Data-Emitting類(lèi)型的Observable
為了讓數(shù)據(jù)庫(kù)在Observable下,發(fā)送字符串型的數(shù)據(jù)。我們可以通過(guò)提供不同的參數(shù),讓just()函數(shù)能夠逐一發(fā)送數(shù)據(jù)。
第2步:創(chuàng)建一個(gè)Data-Consuming類(lèi)型的Observer
前續(xù)代碼片段中的observer能夠使用數(shù)據(jù)庫(kù)observable生成的數(shù)據(jù)。它不但可以接收數(shù)據(jù),而且能夠處理數(shù)據(jù),甚至還可以處理各種錯(cuò)誤。
第3步:調(diào)節(jié)并發(fā)性
最后,我們來(lái)定義并發(fā)的scheduler。程序不但需要通過(guò)subscribeOn(Schedulers.newThread()),在后臺(tái)線程中告知數(shù)據(jù)庫(kù)observable去運(yùn)行;而且需要通過(guò)observeOn(AndroidSchedulers.mainThread())在主線程上告知observer去運(yùn)行。這便是最基本的響應(yīng)式編程代碼。
總結(jié)
在上文中我們探討了響應(yīng)模式的趨勢(shì),以及如何將響應(yīng)式編程集成到應(yīng)用程序的步驟。就Java虛擬機(jī)而言,目前已有多個(gè)響應(yīng)式代碼庫(kù)或框架正在被研發(fā)。它們不但功能全面,而且具有廣泛的兼容性。
譯者介紹
陳峻 (Julian Chen),51CTO社區(qū)編輯,具有十多年的IT項(xiàng)目實(shí)施經(jīng)驗(yàn),善于對(duì)內(nèi)外部資源與風(fēng)險(xiǎn)實(shí)施管控,專注傳播網(wǎng)絡(luò)與信息安全知識(shí)與經(jīng)驗(yàn);持續(xù)以博文、專題和譯文等形式,分享前沿技術(shù)與新知;經(jīng)常以線上、線下等方式,開(kāi)展信息安全類(lèi)培訓(xùn)與授課。
原文標(biāo)題:??Reactive Programming:The Steps To Integrate It Into Your Application???,作者:Gurpreet Singh?