溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

怎么理解Kotlin協(xié)程

發(fā)布時間:2021-11-04 15:01:59 來源:億速云 閱讀:232 作者:iii 欄目:編程語言

這篇文章主要講解了“怎么理解Kotlin協(xié)程”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“怎么理解Kotlin協(xié)程”吧!

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

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

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

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

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

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

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

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

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

怎么理解Kotlin協(xié)程

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

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

怎么理解Kotlin協(xié)程

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

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

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

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

  1. 協(xié)程沒有代表先進(jìn)生產(chǎn)力的發(fā)展要求,先進(jìn)文化的前進(jìn)方向,和最廣大開發(fā)者的根本利益[手動狗頭]。

  2. 協(xié)程在不同編程語言中,它的實際表現(xiàn)有差異,非常不利于開發(fā)者的理解和使用。

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

咸魚翻身

雖說協(xié)程這種協(xié)作式多任務(wù)的組件不能提高程序執(zhí)行的效率,似乎沒有太廣泛的應(yīng)用前景,但這協(xié)程吶,也不能隨意否定自己,因為不知道什么時候,你就突然被歷史進(jìn)程給關(guān)照了。

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

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

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

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

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

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

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

  • 普通的callback代碼:

fun tryPost(){     // 先通過接口驗證權(quán)限 (實際開啟了一個線程,然后等待回調(diào))     findUserPermission(user,callback()){         public void onSuccess(UserPermission response){             // 回調(diào) 如果成功 ,檢查是否有權(quán)限             if(response.hasPermission){             // 如果有權(quán)限,則訪問發(fā)帖接口 (同樣開啟線程,等待回調(diào))                 postContent(content,callback()){                     public void onSuccess(Result response){                         // handle successful response                     }                     public void onFail(){                                              }                 }             }else{                 // 如果無權(quán)限,則......             }         }                  public void onFail(){          }     } }

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

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

  • kotlin的協(xié)程代碼

// 函數(shù)通過suspend關(guān)鍵字標(biāo)識,可以被協(xié)程調(diào)用,具備暫?;謴?fù)的能力 ,實際上仍然使用了io線程來完成接口請求 suspend fun tryfindUserPermission():PermissionResponse {     return withContext(Dispatchers.IO){         findUserPermission(user)     } }  // 函數(shù)通過suspend關(guān)鍵字標(biāo)識,可以被協(xié)程調(diào)用 suspend fun post():Result {     return  withContext(Dispatchers.IO) {         postContent(content)     } }      fun tryPost(){     //啟動一個協(xié)程      launch{      //代碼執(zhí)行到這一行,讓出cpu,進(jìn)入暫停狀態(tài),等待請求成功之后,會恢復(fù)執(zhí)行)      var response = tryfindUserPermission()    // 向后端訪問用戶權(quán)限      if(response.hasPermission){      // 有權(quán)限則開始發(fā)帖 (開啟線程,讓出cpu,暫停執(zhí)行,等待恢復(fù))         var response =  post()          // handle response if need     }   } }

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

  • python的協(xié)程代碼

import asyncio // async 的關(guān)鍵字,表明這個函數(shù)可以被協(xié)程調(diào)用 async def findUserPermission():     // handle http request     ...     ...     return response async def postContent():     // handle http request     ...     ...     return response      async def main(): // 嘗試獲取權(quán)限信息 同樣會讓出cpu,進(jìn)入暫停狀態(tài),等待恢復(fù)     reponse = await findUserPermission()     // 判斷有權(quán)限的情況下,進(jìn)行發(fā)帖     if response.hasPermission :         res = await postContent()         // handle response if need asyncio.run(main())

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

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

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

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

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

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

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

感謝各位的閱讀,以上就是“怎么理解Kotlin協(xié)程”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對怎么理解Kotlin協(xié)程這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關(guān)知識點的文章,歡迎關(guān)注!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI