kotlin Coroutine協程
- 什麼是協程?
-
- 官方描述:
- 協程起源
- 些語言應用到了協程?
- 協程優點
-
- 舉例說明
-
- 異步代碼 & 回調地獄
- 地獄到天堂(使用協程)
- 什麼是程序和線程?
-
- 程序是什麼呢?
- 線程又是什麼呢?
-
- Java中線程具有五種狀态
- 線程和協程的關系
- 開始使用
-
- 環境準備
- 建立協程的幾種方式
-
- 使用方式一:launch:Job(最常用,不阻塞)
- 使用方式二:runBlocking(阻塞)
- 使用方式三:async/await:Deferred(不阻塞)
- 協程中的一些關鍵名稱
- 關系
- 排程器Dispatchers
- suspend
什麼是協程?
官方描述:
協程(英文Coroutines)通過将複雜性放入庫來簡化異步程式設計。程式的邏輯可以在協程中順序地表達,而底層庫會為我們解決其異步性。該庫可以将使用者代碼的相關部分包裝為回調、訂閱相關事件、在不同線程(甚至不同機器)上排程執行,而代碼則保持如同順序執行一樣簡單。
說人話: 協程就像非常輕量級的線程,協程依賴于線程,并且内部實作了相關異步操作
協程起源
「協程 Coroutines」源自 Simula 和 Modula-2 語言,這個術語早在 1958 年就被 Melvin Edward
Conway 發明并用于建構彙程式設計式,說明協程是一種程式設計思想,并不局限于特定的語言。
些語言應用到了協程?
-
Lua語言
Lua從5.0版本開始使用協程,通過擴充庫coroutine來實作。
-
Python語言
正如剛才所寫的代碼示例,python可以通過 yield/send 的方式實作協程。在python 3.5以後, async/await 成為了更好的替代方案。
-
Go語言
Go語言對協程的實作非常強大而簡潔,可以輕松建立成百上千個協程并發執行。
-
Java語言
如上文所說,Java語言并沒有對協程的原生支援,但是某些開源架構模拟出了協程的功能,有興趣的小夥伴可以看一看Kilim架構的源碼:
https://github.com/kilim/kilim
協程優點
- 輕量級,占用更少的系統資源;(線程的代碼,占用的記憶體幾乎是使用協程的兩倍)
- 高效
- 挂起函數,不會造成線程阻塞
- 異步邏輯同步化表達
舉例說明
異步代碼 & 回調地獄
比如我們有個需求,發起了一個異步請求,從服務端查詢使用者的資訊,通過 CallBack 傳回 response:
如果現在需求修改了,查詢使用者資訊→查找該使用者的好友清單→查找該好友的動态(代碼看起來非常臃腫)
地獄到天堂(使用協程)
是不是簡潔到了極緻?這就是 Kotlin 協程的魅力:以同步的方式完成異步任務。
為了更好的了解,在使用協程之前,再講解一下線程和程序
什麼是程序和線程?
程序是什麼呢?
直白地講,程序就是應用程式的啟動執行個體。比如我們運作一個遊戲,打開一個軟體,就是開啟了一個程序。
程序擁有代碼和打開的檔案資源、資料資源、獨立的記憶體空間。
線程又是什麼呢?
線程從屬于程序,是程式的實際執行者。一個程序至少包含一個主線程,也可以有更多的子線程。
線程擁有自己的棧空間。
對作業系統來說,線程是最小的執行單元,程序是最小的資源管理單元。
無論程序還是線程,都是由作業系統所管理的。
Java中線程具有五種狀态
線程不同狀态之間的轉化是誰來實作的呢?是JVM嗎?
并不是。JVM需要通過作業系統核心中的TCB(Thread Control Block)子產品來改變線程的狀态,這一過程需要耗費一定的CPU資源。 在 Java 的 API 中,Thread 類是實作線程最基本的類,每建立一個 Thread 對象,就代表着在作業系統核心啟動了一個線程,如果我們閱讀 Thread 類的源碼,可以發現,它的内部實作是大量的 JNI 調用,因為線程的實作必須由作業系統直接提供支援。
線程和協程的關系
- 輕量級、高效
線程是由系統排程的,線程切換或線程阻塞的開銷都比較大
- 依賴于線程
不能脫離線程而運作
- 挂起時不阻塞線程
協程底層庫也是異步處理阻塞任務,但是這些複雜的操作被底層庫封裝起來,協程代碼的程式流是順序的
- 一個線程可建立任意個協程
- 不同的線程之間切換
- 協程可控
協程底層庫也是異步處理阻塞任務,但是這些複雜的操作被底層庫封裝起來,協程代碼的程式流是順序的
開始使用
環境準備
建立協程的幾種方式
使用方式一:launch:Job(最常用,不阻塞)
使用方式二:runBlocking(阻塞)
使用方式三:async/await:Deferred(不阻塞)
協程中的一些關鍵名稱
關系
作用域和上下文的差別
隻在于使用目的的不同——作用域用于管理協程;而上下文隻是一個記錄協程運作環境的集合
排程器Dispatchers
suspend
suspend 修飾的方法會在在編譯期間被編譯器做特殊處理,這種處理被成為CPS(續體轉換風格) 轉化,suspend 方法會被包裹成 Continuation
Kotlin 編譯器将會為每個挂起函數建立一個狀态機,這個狀态機将為我們管理協程的操作!
挂起函數必須在協程或者另一個挂起函數裡被調用。