Kotlin Coroutine(協程)系列:
1. Kotlin Coroutine(協程) 簡介
2. Kotlin Coroutine(協程) 基本知識編程
協程是可掛起計算的實例。promise
它在概念上相似於線程,在這個意義上,它須要一個代碼塊運行,並具備相似的生命週期,它能夠被建立和啓動,但它不綁定到任何特定的線程。網絡
它能夠在一個線程中掛起其執行,並在另外一個線程中恢復。並且,像future 或 promise那樣,它在完結時可能伴隨着某種結果(值或異常)異步
協程開發人員這樣描述協程:異步編程
協程就像很是輕量級的線程。線程是由系統調度的,線程切換或線程阻塞的開銷都比較大。而協程依賴於線程,可是協程掛起時不須要阻塞線程,幾乎是無代價的,協程是由開發者控制的。因此協程也像用戶態的線程,很是輕量級,一個線程中能夠建立任意個協程。post
如上面所說,協程是由開發者本身控制的,所以在使用協程時咱們必定要記住一點,咱們必須知道咱們使用的協程在什麼時候掛起,它又在什麼時候從新恢復執行,若是無法知道這兩點,那就意味着咱們沒法控制協程,這個時候要慎用協程。性能
一般咱們在Android
中發起一個網絡請求都會經歷以下幾步:spa
Retrofit.Call
Retrofit.Call.enqueue(callback)
方法上面的流程中爲請求任務分配子線程通常都會配合線程池去作,以防止不斷建立線程而產生系統開銷,但在線程真正執行過程當中常常會遇到因磁盤IO或者是網絡請求等操做而致使線程阻塞,而此時當前線程只能阻塞等待,沒法作任何事情,在等待的這段時間裏線程至關於白白了浪費了自身資源,致使線程自身利用率低下。線程
在Android
中改用協程發起網絡請求流程以下:code
在上述流程步驟3中掛起協程後子線程並不會阻塞,此時該子線程能夠被系統分配去作其餘的事情,當協程掛起結束時從新在子線程中恢復執行。這樣該線程就不會存在因阻塞致使的空閒浪費,提升了線程利用率。
總的來講,使用協程能夠最大程度的複用線程,經過讓線程滿載運行,從而達到充分的利用CPU提升系統性能。
使用協程另一個好處就是可讓開發者們告別異步編程中的回調地獄,簡化異步編程,讓寫異步代碼和寫同步代碼同樣簡單,加強了代碼的可讀性、可理解性和可維護性。
舉個例子
假定有個登陸有以下流程:
經常使用實現方式代碼以下:
fun login() {
requestToken { token ->
requestUserInfo(token) { user ->
Log.i("tag", user.toString())
}
}
}
複製代碼
上面的例子是Android
開發中常常會遇到的問題,一個請求依賴前一個請求的結果,這個時候常常會出現這樣的寫法,在第一個請求的成功回調中根據請求結果發起第二個網絡請求。這裏還只存在兩層的嵌套,試想一下,若是嵌套層次出現4次,5次,甚至更多會出現怎樣的狀況,估計開發者本身寫起來都會崩潰。
使用RxJava實現代碼以下:
Single.fromCallable { requestToken() }
.map { token -> requestUserInfo(tokenm) }
.subscribe(
{ user -> Log.i("tag", user.toString()) }, // onSuccess
{ e -> e.printStackTrace() } // onError
)
複製代碼
使用RxJava
的實現方式雖然將回調嵌套改爲了鏈式寫法,閱讀起來要稍微好點,可是依然存在回調並且增長了實現的複雜度,對不熟悉RxJava
的人來講更少增長了難度。
使用協程實現方式代碼以下:
fun login() {
val token = requestToken()
val user = requestUserInfo(token)
Log.i("tag", user.toString())
}
複製代碼
怎麼樣,使用協程的寫法是否是簡便不少,並且看起來很是符合人們的閱讀和理解習慣。