日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
聽(tīng)大佬聊聊Kotlin中把碼仔玩死的:協(xié)程

前言

十載的東河網(wǎng)站建設(shè)經(jīng)驗(yàn),針對(duì)設(shè)計(jì)、前端、開(kāi)發(fā)、售后、文案、推廣等六對(duì)一服務(wù),響應(yīng)快,48小時(shí)及時(shí)工作處理。營(yíng)銷型網(wǎng)站建設(shè)的優(yōu)勢(shì)是能夠根據(jù)用戶設(shè)備顯示端的尺寸不同,自動(dòng)調(diào)整東河建站的顯示方式,使網(wǎng)站能夠適用不同顯示終端,在瀏覽器中調(diào)整網(wǎng)站的寬度,無(wú)論在任何一種瀏覽器上瀏覽網(wǎng)站,都能展現(xiàn)優(yōu)雅布局與設(shè)計(jì),從而大程度地提升瀏覽體驗(yàn)。創(chuàng)新互聯(lián)建站從事“東河網(wǎng)站設(shè)計(jì)”,“東河網(wǎng)站推廣”以來(lái),每個(gè)客戶項(xiàng)目都認(rèn)真落實(shí)執(zhí)行。

本文講的協(xié)程主要以kotlin為主,同時(shí)可能參考python,go,但是會(huì)盡量避免使用代碼,而是嘗試用通俗的語(yǔ)言來(lái)聊協(xié)程的發(fā)展歷程,盡量保證大家都能理解。

近些年,一些編程語(yǔ)言的新貴Go和Kotlin紛紛引入了協(xié)程這個(gè)語(yǔ)言特性,使得協(xié)程這個(gè)似乎十分陌生的概念開(kāi)始頻繁進(jìn)入大家的視野,為了便于理解,開(kāi)發(fā)者們都把它當(dāng)作線程的小弟來(lái)對(duì)待,即輕量級(jí)線程??墒钦嬉?xì)說(shuō)起來(lái),協(xié)程其實(shí)是很早就出現(xiàn)的一個(gè)編程概念,它的出現(xiàn)甚至是是早于線程的,但是就編程語(yǔ)言的江湖地位而言,協(xié)程是不如線程的,所以向線程低頭叫爸爸不奇怪。

看了我上面的介紹,大家一定很納悶,你說(shuō)協(xié)程出現(xiàn)早,有資歷,那為啥幾十年的編程語(yǔ)言發(fā)展下來(lái)就就混成了這副咸魚(yú)樣?線程出現(xiàn)晚,但怎么就一棵星星之火點(diǎn)著了編程語(yǔ)言的草原。成為了編程語(yǔ)言中的重要概念呢??再者,協(xié)程幾十年的咸魚(yú)一條,到如今怎么突然有了夢(mèng)想,翻身把歌唱的呢?

今天就和大家一起來(lái)梳理一下協(xié)程的整個(gè)發(fā)展歷程,希望能幫助大家更加理解協(xié)程。

協(xié)程的出現(xiàn)

咱們先來(lái)說(shuō)說(shuō)協(xié)程的歷史,以及它是怎么混的這么慘的,畢竟悲催的人生都需要一個(gè)解釋。

協(xié)程最早誕生于1958年,被應(yīng)用于匯編語(yǔ)言中(距今已有60多年了),對(duì)它的完整定義發(fā)表于1963 年,協(xié)程是一種通過(guò)代碼執(zhí)行的恢復(fù)與暫停來(lái)實(shí)現(xiàn)協(xié)作式的多任務(wù)的程序組件。

而與此同時(shí),線程的出現(xiàn)則要晚一些,伴隨著操作系統(tǒng)的出現(xiàn),線程大概在1967年被提出。線程作為由操作系統(tǒng)調(diào)度最小執(zhí)行組件,主要用于實(shí)現(xiàn)搶占式的多任務(wù)。

既然大家都搞多任務(wù),按說(shuō)誰(shuí)也不能比誰(shuí)強(qiáng)多少啊,況且協(xié)程還早生幾年,理論上通過(guò)自身努力發(fā)展,在編程語(yǔ)言中占據(jù)核心地位是極有可能的。

但是這協(xié)程的發(fā)展啊,一方面當(dāng)然要靠自我?jiàn)^斗,另一方面,也要考慮歷史進(jìn)程。而上個(gè)世紀(jì)七八九十年代,是計(jì)算機(jī)瘋狂朝著小型化和個(gè)人化的方向演進(jìn)的時(shí)代,計(jì)算機(jī)非常依賴操作系統(tǒng)來(lái)提供用戶交互和壓榨CPU的最大性能,而操作系統(tǒng)怎么來(lái)壓榨計(jì)算機(jī)性能的呢?靠多線程。操作系統(tǒng)跟隨個(gè)人計(jì)算機(jī)的普及之后,編程語(yǔ)言自然也開(kāi)始依賴操作系統(tǒng)提供的接口來(lái)駕馭計(jì)算機(jī)了,線程成了幾乎所有編程語(yǔ)言跳不過(guò)的一個(gè)重要概念,并一直延續(xù)至今。

到這里你可能要問(wèn)了,大家都是搞多任務(wù)的,為什么線程能提升cpu的資源利用率,協(xié)程不能呢?

當(dāng)然有很多其他的原因能解釋,但最本質(zhì)的原因仍然是協(xié)程和線程是有顯著區(qū)別的兩個(gè)概念,到這里我們就要回過(guò)頭來(lái)聊聊什么叫協(xié)作式多任務(wù),什么叫搶占式多任務(wù)?以及這兩種任務(wù)是否是同一種概念?

  • 協(xié)作式多任務(wù):

上圖是一個(gè)壽司生產(chǎn)的部分工序,我們可以把圖中的傳送轉(zhuǎn)盤(pán)和機(jī)器抓手可視作兩個(gè)任務(wù),一起協(xié)作完成了食物的生產(chǎn)。這就是協(xié)作式多任務(wù)。協(xié)作式的多任務(wù)要求任務(wù)之間相互熟悉,才能實(shí)現(xiàn)協(xié)作。

  • 搶占式多任務(wù):

喂金魚(yú)的場(chǎng)景,一把飼料下去,所有金魚(yú)馬上圍上來(lái)一搶而空,這里每個(gè)金魚(yú)都相當(dāng)于一個(gè)任務(wù)線程,這就是搶占式多任務(wù)。而搶占式多任務(wù)(線程)之間不需要了解和配合,只有競(jìng)爭(zhēng)關(guān)系。

上面兩張圖,比較生動(dòng)的展示了協(xié)作式多任務(wù)(協(xié)程)和搶占式多任務(wù)(多線程)之間的區(qū)別。我們能夠發(fā)現(xiàn),協(xié)程更加適合那些相互熟悉的任務(wù)組件通過(guò)密切配合協(xié)作完成某些工作,協(xié)作式多任務(wù)里的“任務(wù)”是一種子程序(可稱為函數(shù))。搶占式多任務(wù)里的任務(wù)則是指能搶占資源的組件或代碼(其實(shí)就是線程),這里的多任務(wù)也就是多線程。所以說(shuō),協(xié)程和線程本來(lái)是差異非常大的兩種概念,他們的能力是不同的,而線程的這種能力正好迎合了那個(gè)時(shí)代的需求。自我?jiàn)^斗+歷史進(jìn)程是線程成功的主要原因。

當(dāng)然,在另一方面,也由于協(xié)程是基于編程語(yǔ)言層面的一種概念,它并沒(méi)有統(tǒng)一定義的接口,因此在不同的語(yǔ)言中實(shí)現(xiàn)后的效果是不同的,這也會(huì)對(duì)開(kāi)發(fā)者造成極大的困擾,不利于它的推廣。而反觀線程,通過(guò)操作系統(tǒng)的統(tǒng)一接口,定義了大體相同的線程使用方式,保證了不同的編程語(yǔ)言都對(duì)線程的使用是大體一致。

講到這里,我們來(lái)總結(jié)下協(xié)程早期發(fā)展不順的原因:

  1. 協(xié)程沒(méi)有代表先進(jìn)生產(chǎn)力的發(fā)展要求,先進(jìn)文化的前進(jìn)方向,和最廣大開(kāi)發(fā)者的根本利益[手動(dòng)狗頭]。
  2. 協(xié)程在不同編程語(yǔ)言中,它的實(shí)際表現(xiàn)有差異,非常不利于開(kāi)發(fā)者的理解和使用。

以上兩點(diǎn),就是協(xié)程幾十年以來(lái)一直不溫不火的原因。我們也看到,雖然看起來(lái)都在搞多任務(wù),但是協(xié)程和線程實(shí)際是沒(méi)有太多交集的。

咸魚(yú)翻身

雖說(shuō)協(xié)程這種協(xié)作式多任務(wù)的組件不能提高程序執(zhí)行的效率,似乎沒(méi)有太廣泛的應(yīng)用前景,但這協(xié)程吶,也不能隨意否定自己,因?yàn)椴恢朗裁磿r(shí)候,你就突然被歷史進(jìn)程給關(guān)照了。

還是從線程說(shuō)起,雖然線程成為編程世界的重要概念,但是在多年的使用過(guò)程中開(kāi)發(fā)者們也逐漸意識(shí)到了它的痛點(diǎn):

  • 線程之間(異步代碼)難以交互難度比較大,往往只能用callback,大量的callback會(huì)代碼難以閱讀和理解,最終讓項(xiàng)目變得難以維護(hù)。

簡(jiǎn)單說(shuō)就是在開(kāi)發(fā)者端,線程之間如何更方便的交互。

而這里協(xié)程能做什么呢?

或許我再重新表達(dá)一下線程的痛點(diǎn):在開(kāi)發(fā)者端,線程之間如何更方便的協(xié)作。

回想一下,我們是怎么介紹協(xié)程的?協(xié)作式多任務(wù)對(duì)吧,還記得上圖中的轉(zhuǎn)盤(pán)和機(jī)器抓手的協(xié)作么?我們當(dāng)時(shí)說(shuō)這兩個(gè)任務(wù)更像是兩個(gè)函數(shù)的協(xié)作,但如果把轉(zhuǎn)盤(pán)和機(jī)器抓手視作兩個(gè)線程呢?借助編譯器,把線程封裝成一個(gè)個(gè)能暫停和恢復(fù)的函數(shù),線程是不是就可以像協(xié)程設(shè)計(jì)的那樣協(xié)作呢?

我們還是從代碼層面來(lái)看看如今協(xié)程是如何被使用的吧。設(shè)計(jì)一個(gè)簡(jiǎn)單的需求:社區(qū)內(nèi)用戶進(jìn)行發(fā)帖時(shí),需要先從后臺(tái)驗(yàn)證發(fā)帖權(quán)限,請(qǐng)求兩個(gè)接口,那么可能我們需要嘗試開(kāi)啟兩個(gè)線程先后來(lái)完成。

  • 普通的callback代碼:
 
 
 
 
  1. fun tryPost(){ 
  2.     // 先通過(guò)接口驗(yàn)證權(quán)限 (實(shí)際開(kāi)啟了一個(gè)線程,然后等待回調(diào)) 
  3.     findUserPermission(user,callback()){ 
  4.         public void onSuccess(UserPermission response){ 
  5.             // 回調(diào) 如果成功 ,檢查是否有權(quán)限 
  6.             if(response.hasPermission){ 
  7.             // 如果有權(quán)限,則訪問(wèn)發(fā)帖接口 (同樣開(kāi)啟線程,等待回調(diào)) 
  8.                 postContent(content,callback()){ 
  9.                     public void onSuccess(Result response){ 
  10.                         // handle successful response 
  11.                     } 
  12.                     public void onFail(){ 
  13.                          
  14.                     } 
  15.                 } 
  16.             }else{ 
  17.                 // 如果無(wú)權(quán)限,則...... 
  18.             } 
  19.         } 
  20.          
  21.         public void onFail(){  
  22.         } 
  23.     } 

這是比較常見(jiàn)的做法,我們需要訪問(wèn)兩次接口,而交互只能在callback中進(jìn)行,但是其實(shí)代碼已經(jīng)很難看了,如果還有其他的邏輯的話,那代碼只會(huì)更加冗雜,難以維護(hù)。

那協(xié)程是怎么解決這種痛點(diǎn)的呢?我們看看(kotlin和python)協(xié)程的代碼如何實(shí)現(xiàn)這種需求:

  • kotlin的協(xié)程代碼
 
 
 
 
  1. // 函數(shù)通過(guò)suspend關(guān)鍵字標(biāo)識(shí),可以被協(xié)程調(diào)用,具備暫?;謴?fù)的能力 ,實(shí)際上仍然使用了io線程來(lái)完成接口請(qǐng)求 
  2. suspend fun tryfindUserPermission():PermissionResponse { 
  3.     return withContext(Dispatchers.IO){ 
  4.         findUserPermission(user) 
  5.     } 
  6. } 
  7.  
  8. // 函數(shù)通過(guò)suspend關(guān)鍵字標(biāo)識(shí),可以被協(xié)程調(diào)用 
  9. suspend fun post():Result { 
  10.     return  withContext(Dispatchers.IO) { 
  11.         postContent(content) 
  12.     } 
  13. } 
  14.      
  15. fun tryPost(){ 
  16.     //啟動(dòng)一個(gè)協(xié)程 
  17.      launch{ 
  18.      //代碼執(zhí)行到這一行,讓出cpu,進(jìn)入暫停狀態(tài),等待請(qǐng)求成功之后,會(huì)恢復(fù)執(zhí)行) 
  19.      var response = tryfindUserPermission()    // 向后端訪問(wèn)用戶權(quán)限 
  20.      if(response.hasPermission){ 
  21.      // 有權(quán)限則開(kāi)始發(fā)帖 (開(kāi)啟線程,讓出cpu,暫停執(zhí)行,等待恢復(fù)) 
  22.         var response =  post() 
  23.          // handle response if need 
  24.     } 
  25.   } 

可以看到,在kotlin中,協(xié)程通過(guò)把線程里的代碼封裝成一種能暫停/恢復(fù)的函數(shù),讓多線程之間的交互就像普通的函數(shù)一樣簡(jiǎn)單,不需要callback。

  • python的協(xié)程代碼
 
 
 
 
  1. import asyncio 
  2. // async 的關(guān)鍵字,表明這個(gè)函數(shù)可以被協(xié)程調(diào)用 
  3. async def findUserPermission(): 
  4.     // handle http request 
  5.     ... 
  6.     ... 
  7.     return response 
  8. async def postContent(): 
  9.     // handle http request 
  10.     ... 
  11.     ... 
  12.     return response 
  13.      
  14. async def main(): 
  15. // 嘗試獲取權(quán)限信息 同樣會(huì)讓出cpu,進(jìn)入暫停狀態(tài),等待恢復(fù) 
  16.     reponse = await findUserPermission() 
  17.     // 判斷有權(quán)限的情況下,進(jìn)行發(fā)帖 
  18.     if response.hasPermission : 
  19.         res = await postContent() 
  20.         // handle response if need 
  21. asyncio.run(main()) 

python通過(guò)協(xié)程處理這種問(wèn)題本質(zhì)和kotlin是一致的。

相信大家也能看到,協(xié)程在不同的語(yǔ)言中的表現(xiàn)方式是有差異的

通過(guò)上面幾段偽代碼,我們能夠比較清楚看到,協(xié)程能非常明顯的簡(jiǎn)化了線程之間協(xié)作復(fù)雜度,讓我們可以以編寫(xiě)同步代碼的方式來(lái)編寫(xiě)異步代碼,極大的簡(jiǎn)化你的邏輯,讓你的代碼容易維護(hù)。

那么協(xié)程是如何做到的呢?

雖然不同的語(yǔ)言中,協(xié)程有所差異,但是原理都差不多,編程語(yǔ)言的編譯器通過(guò)一些關(guān)鍵字(kotlin中用suspend,python中用async等)來(lái)修飾函數(shù),在編譯期間根據(jù)關(guān)鍵字生成一些線程相關(guān)的代碼來(lái)實(shí)現(xiàn)函數(shù)的暫?;謴?fù)的功能,從而實(shí)現(xiàn)把線程相關(guān)的代碼留在編譯期間產(chǎn)生,在開(kāi)發(fā)層面就能提供像普通函數(shù)一般的協(xié)作方式。

因?yàn)榻鉀Q了這個(gè)痛點(diǎn),協(xié)程開(kāi)始變得越來(lái)越受開(kāi)發(fā)者歡迎。而協(xié)程通過(guò)編譯器的幫助把線程相關(guān)的代碼留在了編譯期間產(chǎn)生,開(kāi)發(fā)者可以通過(guò)操作協(xié)程就可以達(dá)到使用線程的目的,所以現(xiàn)在大家認(rèn)為協(xié)程是一種輕量級(jí)的線程。

對(duì)于多線程的協(xié)作,或者說(shuō)異步代碼之間的協(xié)作并不是只有協(xié)程一家解決方案,在JS中,有promise,Java中有RxJava等等,他們都致力于解決異步編程的相關(guān)問(wèn)題,希望能以編寫(xiě)同步代碼的方式來(lái)寫(xiě)異步代碼,目前來(lái)看,他們都做的很不錯(cuò)。

總結(jié)

大家對(duì)于協(xié)程的理解有很多分歧,但是對(duì)我而言,協(xié)程其實(shí)得分兩個(gè)階段來(lái)理解:

  • 在協(xié)程誕生之初,只是用來(lái)解決編程中的某些特殊問(wèn)題的編程組件,它的多任務(wù)更像多個(gè)函數(shù)的組合協(xié)作執(zhí)行,那個(gè)時(shí)候,協(xié)程其實(shí)更像是一種具備暫?;謴?fù)的函數(shù)。但是這種功能似乎并不受歡迎,因此協(xié)程在很長(zhǎng)一段時(shí)間內(nèi)都是比較小眾的。(此時(shí)協(xié)程和線程關(guān)系并不大)
  • 如今它成為底層支持多線程的協(xié)作式多任務(wù)組件,很好的解決了線程協(xié)作的痛點(diǎn),同時(shí)也逐漸變得越來(lái)越受歡迎,協(xié)程和線程的關(guān)系更加親密,它們似乎也變得更加相似。(如今你可以把協(xié)程視作一種輕量級(jí)線程)

而協(xié)程的發(fā)展歷程,其實(shí)也就是經(jīng)歷了這兩個(gè)階段。


當(dāng)前文章:聽(tīng)大佬聊聊Kotlin中把碼仔玩死的:協(xié)程
網(wǎng)頁(yè)網(wǎng)址:http://m.5511xx.com/article/djiceei.html