深入理解 Kotlin 協程 Coroutine(3)
前面有兩篇文章介紹過協程,加上這篇,基本上介紹得差不多了~
上周在北京的活動上給大家分享了一下協程,發現大家對於協程最大的困惑是:我為什麼要用它。。。
正好,前面一直想要再寫篇協程的文章,這次讓我們再來回顧一下其中的一些問題。
我們為什麼要用協程?
這個問題對於新接觸協程的朋友來說確實很容易讓人困惑,那麼我們就來看看協程給我們帶來什麼吧。
協程是一種語法糖協程的出現是來解決非同步問題的,但它本身卻不提供非同步的能力,額這就很搞笑了,你來自於猴子與逗比嗎?當然不是,協程某種意義上更像是一種語法糖,它為我們隱藏了非同步調用和回調的細節,讓我們更關注於業務邏輯的實現。
協程讓代碼更簡潔協程可以允許我們用同步代碼的方式寫出非同步代碼的功能。
這是一段 Android 的代碼示例,請注意這個賦值操作,它實際上是切換到 UI 線程之後運行的,而 await 當中的 loadImage(url) 卻是在 IO 線程中運行,所以我們一方面知道協程的非同步功能是有線程在後面支持的,另一方面我們也知道非同步線程回調可以用協程直接簡化為一個簡單的賦值。
協程讓非同步異常處理更方便如果你的非同步代碼出現異常,通常你會在你的回調中加入一個 onError 來傳遞這個異常信息:
而在協程的只支持下,我們只要按照同步代碼的異常捕獲方式進行捕獲就可以了:
協程更輕量級通常比較傳統的伺服器實現,一個用戶請求接入後會給他開一個線程來等待和處理它的請求。這樣是非常不經濟的,因為這個用戶有可能就是來逗你玩的,建立連接之後半天來一個位元組,就這樣你還得付出一個線程的代價來服務他,尷尬。如果用協程,那麼就要輕量多了,因為協程只是一塊兒內存,不像線程那樣還要對應操作系統內核線程(印象中 Hotpot 的實現就是這樣)。
用協程的理由我個人感覺也就這些了。一句話,協程是一種輕量級的方便操作非同步代碼的語法糖,而它本身不提供非同步能力。
為什麼說它是語法糖?
這樣一句代碼其實在編譯完之後會生成一些新的類,async 後面的 Lambda 就會被編譯成一個 CoroutineImpl 類的子類實例,大家只需要按照我經常提到的查看 Kotlin 位元組碼的方法去看看就知道了。
那麼這個類究竟是個什麼呢?
它首先是個 Lambda ,這沒毛病。其次,它是一個 Continuation,了解協程的朋友似乎要知道什麼了,沒錯,這貨與我們自己在啟動協程時傳入的 Continuation 實例是同樣的東西,而且我們可以注意到構造方法當中有一個叫做 completion 的欄位,不要驚訝,那就是我們傳入的 Continuation。
實際上,我們通過編譯器編譯出來的位元組碼發現,create 方法當中會通過我們的這個 Lambda 表達式創建一個新的 CoroutineImpl 實例,而 doResume 這個抽象方法其實就是我們的 Lambda 表達式的內容了。
在這裡我們還看到了 facade:
其中 當中就會處理各個攔截器,來完成線程調度或者其他操作,也就是說 facade 返回的 Continuation 實例就是經過類似下面這樣的攔截器返回的實例了:
協程是如何啟動的?
我們再來看看協程是如何啟動的。我們啟動協程的時候通常會調用 startCoroutine 或者 createCoroutine,它們都會調用到一個方法:
我們已經知道我們的調用者實際上就是一個 CoroutineImpl 的實例,我們只需要關注 else 分支即可,這時候調用我們前面已經見到的 create 方法再創建一個 CoroutineImpl 實例,並把 completion 這個對象傳給它,而 facade 實際上就會觸發攔截器的操作,最終返回的就是經過攔截器處理之後的 Continuation 實例了。
創建完協程之後,就是啟動的邏輯:
直接調用 方法,結果怎樣呢?由於攔截器都是我們自己提供的,比較直觀,我們暫且不提,通常情況下,這個 resume 方法最終本質上調用的還是 CoroutineImpl 的 方法:
會首先觸發一次 doResume 的調用,這個調用也就是我們自己的協程代碼了,直到遇到第一個 suspend 調用,那麼這時候協程就會被掛起,等待非同步操作執行完成之後再來調用我們的 resume/resumeWithException 方法來通知我們數據回來了或者異常發生了。這個過程直到整個協程執行流程結束。
我們稍微關注一下 Continuation 介面:
再來看看我們通常的回調版本:
除了協程上下文之外,剩下的兩個方法與我們的回調又有什麼區別呢?
小結
協程是什麼?它就是用來簡化你的非同步回調代碼的語法糖!


TAG:Kotlin |
※Windows PowerShell進階 理解Module
※MapReduce Shuffle深入理解
※從One-hot,Word embedding到Transformer,一步步教你理解Bert
※徹底理解cookie、session、token
※快速理解Token,Cookie,Session
※我所理解的#ShotoniPhone
※Cookie,Session和Token概念的正確理解
※理解 Linux 中的 /etc/services 文件
※阿里CEO張勇:我們理解AI是Alibaba Intelligence
※理解 OutOfMemoryError 異常
※Glibc堆漏洞利用基礎-深入理解ptmalloc2 part1
※深入理解 ES Modules
※深入理解 Web Server 原理與實踐:Nginx
※理解 Python 的 for 循環
※簡單理解Vue中的nextTick
※理解foreach, for in, for of 之間的異同
※徹底理解 Node.js 中的回調(Callback)函數
※我所理解的 Smartisan OS
※用汽車比喻理解OOP-Jonathan Kuhl
※通過 Q-learning 深入理解強化學習