欧美一级特黄大片做受成人-亚洲成人一区二区电影-激情熟女一区二区三区-日韩专区欧美专区国产专区

java異步編程有哪些方式

本篇內(nèi)容介紹了“java異步編程有哪些方式”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

公司主營(yíng)業(yè)務(wù):成都網(wǎng)站設(shè)計(jì)、成都網(wǎng)站建設(shè)、移動(dòng)網(wǎng)站開(kāi)發(fā)等業(yè)務(wù)。幫助企業(yè)客戶真正實(shí)現(xiàn)互聯(lián)網(wǎng)宣傳,提高企業(yè)的競(jìng)爭(zhēng)能力。創(chuàng)新互聯(lián)公司是一支青春激揚(yáng)、勤奮敬業(yè)、活力青春激揚(yáng)、勤奮敬業(yè)、活力澎湃、和諧高效的團(tuán)隊(duì)。公司秉承以“開(kāi)放、自由、嚴(yán)謹(jǐn)、自律”為核心的企業(yè)文化,感謝他們對(duì)我們的高要求,感謝他們從不同領(lǐng)域給我們帶來(lái)的挑戰(zhàn),讓我們激情的團(tuán)隊(duì)有機(jī)會(huì)用頭腦與智慧不斷的給客戶帶來(lái)驚喜。創(chuàng)新互聯(lián)公司推出丹陽(yáng)免費(fèi)做網(wǎng)站回饋大家。

為什么需要異步?

操作系統(tǒng)可以看作是個(gè)虛擬機(jī)(VM),進(jìn)程生活在操作系統(tǒng)創(chuàng)造的虛擬世界里。進(jìn)程不用知道到底有多少 core 多少內(nèi)存,只要進(jìn)程不要索取的太過(guò)分,操作系統(tǒng)就假裝有無(wú)限多的資源可用。

基于這個(gè)思想,線程(Thread)的個(gè)數(shù)并不受硬件限制:你的程序可以只有一個(gè)線程、也可以有成百上千個(gè)。操作系統(tǒng)會(huì)默默做好調(diào)度,讓諸多線程共享有限的 CPU 時(shí)間片。這個(gè)調(diào)度的過(guò)程對(duì)線程是完全透明的。

那么,操作系統(tǒng)是怎樣做到在線程無(wú)感知的情況下調(diào)度呢?答案是上下文切換(Context Switch),簡(jiǎn)單來(lái)說(shuō),操作系統(tǒng)利用軟中斷機(jī)制,把程序從任意位置打斷,然后保存當(dāng)前所有寄存器——包括最重要的指令寄存器 PC 和棧頂指針 SP,還有一些線程控制信息(TCB),整個(gè)過(guò)程會(huì)產(chǎn)生數(shù)個(gè)微秒的 overhead。

java異步編程有哪些方式

然而作為一位合格的程序員,你一定也聽(tīng)說(shuō)過(guò),線程是昂貴的:

  •  線程的上下文切換有不少的代價(jià),占用寶貴的 CPU 時(shí)間;

  •  每個(gè)線程都會(huì)占用一些(至少 1 頁(yè))內(nèi)存。

這兩個(gè)原因驅(qū)使我們盡可能避免創(chuàng)建太多的線程,而異步編程的目的就是消除 IO wait 阻塞——絕大多數(shù)時(shí)候,這是我們創(chuàng)建一堆線程、甚至引入線程池的罪魁禍?zhǔn)住?/p>

Continuation

回調(diào)函數(shù)知道的人很多,但了解 Continuation 的人不多。Continuation 有時(shí)被晦澀地翻譯成“計(jì)算續(xù)體”,咱們還是直接用單詞好了。

把一個(gè)計(jì)算過(guò)程在中間打斷,剩下的部分用一個(gè)對(duì)象表示,這就是 Continuation。操作系統(tǒng)暫停一個(gè)線程時(shí)保存的那些現(xiàn)場(chǎng)數(shù)據(jù),也可以看作一個(gè) Continuation。有了它,我們就能在這個(gè)點(diǎn)接著剛剛的斷點(diǎn)繼續(xù)執(zhí)行。

打斷一個(gè)計(jì)算過(guò)程聽(tīng)起來(lái)很厲害吧!實(shí)際上它每時(shí)每刻都在發(fā)生——假設(shè)函數(shù) f() 中間調(diào)用了 g(),那 g() 運(yùn)行完成時(shí),要返回到 f() 剛剛調(diào)用 g() 的地方接著執(zhí)行。這個(gè)過(guò)程再自然不過(guò)了,以至于所有編程語(yǔ)言(匯編除外)都把它掩藏起來(lái),讓你在編程中感覺(jué)不到調(diào)用棧的存在。

java異步編程有哪些方式

操作系統(tǒng)用昂貴的軟中斷機(jī)制實(shí)現(xiàn)了棧的保存和恢復(fù)。那有沒(méi)有別的方式實(shí)現(xiàn) Continuation 呢?最樸素的想法就是,把所有用得到的信息包成一個(gè)函數(shù)對(duì)象,在調(diào)用 g() 的時(shí)候一起傳進(jìn)去,并約定:一旦 g() 完成,就拿著結(jié)果去調(diào)用這個(gè) Continuation。

這種編程模式被稱為 Continuation-passing style(CPS):

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

  2.  把調(diào)用者 f() 還未執(zhí)行的部分包成一個(gè)函數(shù)對(duì)象 cont,一同傳給被調(diào)用者 g();

  3.  正常運(yùn)行 g() 函數(shù)體;

  4.  g() 完成后,連同它的結(jié)果一起回調(diào) cont,從而繼續(xù)執(zhí)行 f() 里剩余的代碼。

再拿 Wikipedia 上的定義鞏固一下:

A function written in continuation-passing style takes an extra argument: an explicit "continuation", i.e. a function of one argument. When the CPS function has computed its result value, it "returns" it by calling the continuation function with this value as the argument.

CPS 風(fēng)格的函數(shù)帶一個(gè)額外的參數(shù):一個(gè)顯式的 Continuation,具體來(lái)說(shuō)就是個(gè)僅有一個(gè)參數(shù)的函數(shù)。當(dāng) CPS 函數(shù)計(jì)算完返回值時(shí),它“返回”的方式就是拿著返回值調(diào)用那個(gè) Continuation。

你應(yīng)該已經(jīng)發(fā)現(xiàn)了,這也就是回調(diào)函數(shù),我只是換了個(gè)名字而已。

異步的樸素實(shí)現(xiàn):Callback

光有回調(diào)函數(shù)其實(shí)并沒(méi)有卵用。對(duì)于純粹的計(jì)算工作,Call Stack 就很好,為何要費(fèi)時(shí)費(fèi)力用回調(diào)來(lái)做 Continuation 呢?你說(shuō)的對(duì),但僅限于沒(méi)有 IO 的情況。我們知道 IO 通常要比 CPU 慢上好幾個(gè)數(shù)量級(jí),在 BIO 中,線程發(fā)起 IO 之后只能暫停,然后等待 IO 完成再由操作系統(tǒng)喚醒。

var input = recv_from_socket()  // Block at syscall recv()  var result = calculator.calculate(input)  send_to_socket(result) // Block at syscall send()

而異步 IO 中,進(jìn)程發(fā)起 IO 操作時(shí)也會(huì)一并輸入回調(diào)(也就是 Continuation),這大大解放了生產(chǎn)力——現(xiàn)場(chǎng)無(wú)需等待,可以立即返回去做其他事情。一旦 IO 成功后,AIO 的 Event Loop 會(huì)調(diào)用剛剛設(shè)置的回調(diào)函數(shù),把剩下的工作完成。這種模式有時(shí)也被稱為 Fire and Forget。

recv_from_socket((input) -> {      var result = calculator.calculate(input)      send_to_socket(result) // ignore result  })

就這么簡(jiǎn)單,通過(guò)我們自己實(shí)現(xiàn)的 Continuation,線程不再受 IO 阻塞,可以自由自在地跑滿 CPU。

一顆語(yǔ)法糖:Promise

回調(diào)函數(shù)哪里都好,就是不大好用,以及太丑了。

第一個(gè)問(wèn)題是可讀性大大下降,由于我們繞開(kāi)操作系統(tǒng)自制 Continuation,所有函數(shù)調(diào)用都要傳入一個(gè) lambda 表達(dá)式,你的代碼看起來(lái)就像要起飛一樣,縮進(jìn)止不住地往右挪(the "Callback Hell")。

第二個(gè)問(wèn)題是各種細(xì)節(jié)處理起來(lái)很麻煩,比如,考慮下異常處理,看來(lái)傳一個(gè) Continuation 還不夠,最好再傳個(gè)異常處理的 callback。

Promise 是對(duì)異步調(diào)用結(jié)果的一個(gè)封裝,在 Java 中它叫作 CompletableFuture (JDK8) 或者 ListenableFuture (Guava)。Promise 有兩層含義:

第一層含義是:我現(xiàn)在還不是真正的結(jié)果,但是承諾以后會(huì)拿到這個(gè)結(jié)果。這很容易理解,異步的任務(wù)遲早會(huì)完成,調(diào)用者如果比較蠢萌,他也可以用 Promise.get() 強(qiáng)行要拿到結(jié)果,順便阻塞了當(dāng)前線程,異步變成了同步。

第二層含義是:如果你(調(diào)用者)有什么吩咐,就告訴我好了。這就有趣了,換句話說(shuō),回調(diào)函數(shù)不再是傳給 g(),而是 g() 返回的 Promise,比如之前那段代碼,我們用 Promise 來(lái)書(shū)寫(xiě),看起來(lái)順眼了不少。

var promise_input = recv_from_socket()  promise_input.then((input) -> {      var result = calculator.calculate(input)      send_to_socket(result) // ignore result  })

Promise 改善了 Callback 的可讀性,也讓異常處理稍稍優(yōu)雅了些,但終究是顆語(yǔ)法糖。

反應(yīng)式編程

反應(yīng)式(Reactive)最早源于函數(shù)式編程中的一種模式,隨著微軟發(fā)起 ReactiveX 項(xiàng)目并一步步壯大,被移植到各種語(yǔ)言和平臺(tái)上。Reactive 最初在 GUI 編程中有廣泛的應(yīng)用,由于異步調(diào)用的高性能,很快也在服務(wù)器后端領(lǐng)域遍地開(kāi)花。

Reactive 可以看作是對(duì) Promise 的極大增強(qiáng),相比 Promise,反應(yīng)式引入了流(Flow)的概念。ReactiveX 中的事件流從一個(gè) Observable 對(duì)象流出,這個(gè)對(duì)象可以是一個(gè)按鈕,也可以是 Restful API,總之,它能被外界觸發(fā)。與 Promise 不同的是,事件可能被觸發(fā)多次,所以處理代碼也會(huì)被多次調(diào)用。

一旦允許調(diào)用多次,從數(shù)據(jù)流動(dòng)的角度看,事實(shí)上模型已經(jīng)是 Push 而非 Pull。那么問(wèn)題來(lái)了,如果調(diào)用頻率非常高,以至于我們處理速度跟不上了怎么辦?所以 RX 框架又引入了 Backpressure 機(jī)制來(lái)進(jìn)行流控,最簡(jiǎn)單的流控方式就是:一旦 buffer 滿,就丟棄掉之后的事件。

ReactiveX 框架的另一個(gè)優(yōu)點(diǎn)是內(nèi)置了很多好用的算子,比如:merge(Flow 合并),debounce(開(kāi)關(guān)除顫)等等,方便了業(yè)務(wù)開(kāi)發(fā)。下面是一個(gè) RxJava 的例子:

java異步編程有哪些方式

CPS 變換:Coroutine 與 async/await

無(wú)論是反應(yīng)式還是 Promise,說(shuō)到底仍然沒(méi)有擺脫手工構(gòu)造 Continuation:開(kāi)發(fā)者要把業(yè)務(wù)邏輯寫(xiě)成回調(diào)函數(shù)。對(duì)于線性的邏輯基本可以應(yīng)付自如,但是如果邏輯復(fù)雜一點(diǎn)呢?(比如,考慮下包含循環(huán)的情況)

java異步編程有哪些方式

有些語(yǔ)言例如 C#,JavaScript 和 Python 提供了 async/await 關(guān)鍵字。與 Reactive 一樣,這同樣出自微軟 C# 語(yǔ)言。在這些語(yǔ)言中,你會(huì)感到前所未有的爽感:異步編程終于擺脫了回調(diào)函數(shù)!唯一要做的只是在異步函數(shù)調(diào)用時(shí)加上 await,編譯器就會(huì)自動(dòng)把它轉(zhuǎn)化為協(xié)程(Coroutine),而非昂貴的線程。

魔法的背后是 CPS 變換,CPS 變換把普通函數(shù)轉(zhuǎn)換成一個(gè) CPS 的函數(shù),即 Continuation 也能作為一個(gè)調(diào)用參數(shù)。函數(shù)不僅能從頭運(yùn)行,還能根據(jù) Continuation 的指示繼續(xù)某個(gè)點(diǎn)(比如調(diào)用 IO 的地方)運(yùn)行。

可以看到,函數(shù)已經(jīng)不再是一個(gè)函數(shù)了,而是變成一個(gè)狀態(tài)機(jī)。每次 call 它、或者它 call 其他異步函數(shù)時(shí),狀態(tài)機(jī)都會(huì)做一些計(jì)算和狀態(tài)輪轉(zhuǎn)。說(shuō)好的 Continuation 在哪呢?就是對(duì)象自己(this)啊。

CPS 變換實(shí)現(xiàn)非常復(fù)雜,尤其是考慮到 try-catch 之后。但是沒(méi)關(guān)系,復(fù)雜性都在編譯器里,用戶只要學(xué)兩個(gè)關(guān)鍵詞即可。這個(gè)特性非常優(yōu)雅,比 Java 那個(gè)廢柴的 CompletableFuture 不知道高到哪去了

JVM 上也有一個(gè)實(shí)現(xiàn):electronicarts/ea-async,原理和 C# 的 async/await 類似,在編譯期修改 Bytecode 實(shí)現(xiàn) CPS 變換。

終極方案:用戶態(tài)線程

有了 async/await,代碼已經(jīng)簡(jiǎn)潔很多了,基本上和同步代碼無(wú)異。是否有可能讓異步代碼和同步代碼完全一樣呢?聽(tīng)起來(lái)就像免費(fèi)午餐,但是的確可以做到!

用戶態(tài)線程的代表是 Golang。JVM 上也有些實(shí)現(xiàn),比如 Quasar,不過(guò)因?yàn)?JDBC、Spring 這些周邊生態(tài)(它們占據(jù)了大部分 IO 操作)的缺失基本沒(méi)有什么用。

關(guān)注公眾號(hào)Java技術(shù)棧,在后臺(tái)回復(fù):面試,可以獲取我整理的 Java 多線程系列面試題和答案,非常齊全。

用戶態(tài)線程是把操作系統(tǒng)提供的線程機(jī)制完全拋棄,換句話說(shuō),不去用這個(gè) VM 的虛擬化機(jī)制。比如硬件有 8 個(gè)核心,那就創(chuàng)建 8 個(gè)系統(tǒng)線程,然后把 N 個(gè)用戶線程調(diào)度到這 8 個(gè)系統(tǒng)線程上跑。N 個(gè)用戶線程的調(diào)度在用戶進(jìn)程里實(shí)現(xiàn),由于一切都在進(jìn)程內(nèi)部,切換代價(jià)要遠(yuǎn)遠(yuǎn)小于操作系統(tǒng) Context Switch。

java異步編程有哪些方式

另一方面,所有可能阻塞系統(tǒng)級(jí)線程的事情,例如 sleep()、recv() 等,用戶態(tài)線程一定不能碰,否則它一旦阻塞住也就帶著那 8 個(gè)系統(tǒng)線程中的一個(gè)阻塞了。Go Runtime 接管了所有這樣的系統(tǒng)調(diào)用,并用一個(gè)統(tǒng)一的 Event loop 來(lái)輪詢和分發(fā)。

另外,由于用戶態(tài)線程很輕量,我們完全沒(méi)必要再用線程池,如果需要開(kāi)線程就直接創(chuàng)建。比如 Java 中的 WebServer 幾乎一定有個(gè)線程池,而 Go 可以給每個(gè)請(qǐng)求開(kāi)辟一個(gè) goroutine 去處理。并發(fā)編程從未如此美好!

總結(jié)

以上方案中,Promise、Reactive 本質(zhì)上還是回調(diào)函數(shù),只是框架的存在一定程度上降低了開(kāi)發(fā)者的心智負(fù)擔(dān)。而 async/await 和用戶態(tài)線程的解決方案要優(yōu)雅和徹底的多,前者通過(guò)編譯期的 CPS 變換幫用戶創(chuàng)造出 CPS 式的函數(shù)調(diào)用;后者則繞開(kāi)操作系統(tǒng)、重新實(shí)現(xiàn)一套線程機(jī)制,一切調(diào)度工作由 Runtime 接管。

不知道是不是因?yàn)闅v史包袱太重,Java 語(yǔ)言本身提供的異步編程支持弱得可憐,即便是 CompletableFuture 還是在 Java 8 才引入,其后果就是很多庫(kù)都沒(méi)有異步的支持。雖然 Quasar 在沒(méi)有語(yǔ)言級(jí)支持的情況下引入了 CPS 變換,但是由于缺少周邊生態(tài)的支持,實(shí)際很難用在項(xiàng)目中。

“java異步編程有哪些方式”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!

文章題目:java異步編程有哪些方式
網(wǎng)頁(yè)地址:http://aaarwkj.com/article6/ipdgog.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供商城網(wǎng)站、App開(kāi)發(fā)、企業(yè)網(wǎng)站制作、虛擬主機(jī)、App設(shè)計(jì)、網(wǎng)站內(nèi)鏈

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

網(wǎng)站建設(shè)網(wǎng)站維護(hù)公司
亚洲禁看av一区不卡| 俩小伙探花专约老熟女| 日产中文乱码字幕无线观看| 黄色三级视频久久久| 国产女同av一区二区三区| 亚洲情色精品国产一区| 香蕉视频欧美日韩国产| 美女高潮呻吟免费观看久久久| 粉嫩极品国产在线观看| 日本人妻中文字幕一区| 日韩一区欧美中文字幕| 91超碰在线观看中文| 亚洲中文字幕一二区日韩| 欧美日韩一区精品视频| 国产三级亚洲三级在线理论| 亚洲成人精品青青香蕉| 久视频这里只有精品99| 亚洲日本韩国美女二区| 日韩av高清不卡一区二区三区| 99热久久精品免费精品| 亚洲精品一区二区三区三州| 五月婷婷丁香噜噜噜噜| 免费中文字幕av电影| 日韩欧美 高清一区| 森泽佳奈在线视频观看| 日韩高清av不卡一区二区三区| 国产日韩熟女中文字幕| 中文字幕日韩午夜精品| 亚洲欧美丝袜清纯另类| 亚洲一区二区三区不卡视频| 精品亚洲韩国一区二区三区| 日本在线高清精品人妻| 91在线播放国产视频| 91福利社区欧美大片| 青青草针对华人在线视频| 国产又粗又猛又爽黄老大爷 | 国产午夜激情自拍视频| 久久国产精品av在线观看| 一区二区不卡中文av| 无套内射精品一区二区| 成人午夜欧美熟妇小视频|