我在 kotlin讀書會的日子(四): 導讀 coroutines

楊舒安
3 min readJun 21, 2020

(6月21日的進度:coroutines)

因為讀書會的指定書本用android當coroutines的例子,就讓我想起去年的Google I/O大會,影片也是以internet的權限為例:

大約在3分40秒的地方,針對主執行序阻塞的情形,提出三種解決方法:

(上圖可搭配:Kotlin Coroutines 一起閱讀)

並分析理想的處理方式:

最後coroutines勝出...

好的,讓我們歡迎主角coroutines出場(拍手:%%%%%%%% → 鼓掌聲)

一. 什麼是coroutines?(協同程序)

(一)意義:
coroutines的中文翻譯為「協程」,「深入淺出kotlin」一書中形容協程就像「輕量的執行緒」(light-weight threads)。使用協同程序的意義就在於,啟動一個背景工作時,同時讓其他程式不需要等待工作完成就可以做別的事情,用戶體驗會比較好。(鄉民翻譯:使用者用起來快樂,客戶付錢就會乾脆

(二)優點:
1. 解決傳統執行緒的困擾:
影片及書本中都以「在main thread連接internet」為例,由於android明令禁止應用程式在主執行緒存取網路,因此,此時主執行緒會被阻塞。而傳統的執行序在主執行緒阻塞未被移除前,是不會再執行其他作業的,coroutines也是執行緒,只不過在這種情形會被暫停,但是不會阻塞父執行緒。

2. 很適合執行背景工作:
如(一)所述,使用協同程序的好處就在於,啟動一個背景工作時,同時讓其他程式不需要等待工作完成就可以做別的事情,用戶體驗會比較好。(Experimental Kotlin feature that allows work to be performed in the background. For example, You do not want your user to be stuck waiting for them to complete before they can continue using your app. Coroutines allow you to specify work that happens in the background of your application, or asynchronously.)

3. 輕量的執行緒(coroutines are light-weight threads)
(ps. 但是用多了,還是有可能會讓CPU當掉啊...看例子)

(三)注意事項:
This is a companion version for Kotlin 1.3.71 release

二. 開始使用coroutines:

(一)協程建立函式1: GlobalScope / launch:

1. 定義:
(1) launch是「 協程建立函數」(coroutine builder functions)
(2) GlobalScope meaning that the lifetime of the new coroutine is limited only by the lifetime of the whole application.

2. 舉例:Your first coroutine

3. 補充:影片中10:30–11:00有對於launch的介紹

(二)協程建立函式2:async/Deferred
1. async:
(1)使用協程程式庫的async函數時,該函數要求一個引數,指定置於後台工作的lambda運算式, async協程建立函數的方式與lanuch不同,async返回類型是Deferred, 表示任務還沒有結束, 會在未來某個時間點完成
(官網關於async的介紹:async is just like launch. It starts a separate coroutine which is a light-weight thread that works concurrently with all the other coroutines. The difference is that launch returns a Job and does not carry any resulting value, while async returns a Deferred — a light-weight non-blocking future that represents a promise to provide a result later. You can use .await() on a deferred value to get its eventual result, but Deferred is also a Job, so you can cancel it if needed.
官網資料請參考:https://kotlinlang.org/docs/reference/coroutines/composing-suspending-functions.html#concurrent-using-async)

(2) await: Deferred類型有個await函數可供呼叫,await函數也會暫停下一個任務,直到延遲的任務結束

(三)暫停函式suspend:
花個10分鐘來看個影片了解一下

如果您覺得上面的video太難的話,建議降低難度,先聽下方的解說:

1. What is suspend?
The keyword suspend is Kotlin’s way of marking a function, or function type, available to coroutines. When a coroutine calls a function marked suspend, instead of blocking until that function returns like a normal function call, it suspends execution until the result is ready then it resumes where it left off with the result. While it’s suspended waiting for a result, it unblocks the thread that it’s running on so other functions or coroutines can run.
(資料來源:https://codelabs.developers.google.com/codelabs/kotlin-coroutines/index.html#3 )

2. For example:
(1). 基礎:your first suspending function
(2). 進階:Composing Suspending Functions

3. 需注意:
(1) suspend function 可以被其他的 suspend function 調用,但是不能被一般的 function 調用
(2) delay函式前面必須加上suspend(從其他函式呼叫時,那個函式也必須加上suspend)

4. 說明:delay函式可暫停目前的協同程序

(四)runBlocking:
1. 定義: the coroutine builder

2. 優點:
(1) 在先前介紹Globalscope.launch時,會遇到一個問題,同時使用delay(…) 和Thread.sleep(…)時,It is easy to lose track of which one is blocking and which one is not. 而使用runBlocking可以解決這個問題
(2) 承上,比較一下 delay() 及 Thread.sleep():
they are similar, but delay() is better. (cause it doesn’t block a thread, but only suspends the coroutine itself. The thread is returned to the pool while the coroutine is waiting, and when the waiting is done, the coroutine resumes on a free thread in the pool.)

3. 缺點:
在這種情形下,很容易就會run out of memory,這時就建議改用GlobalScope.launch
(Cause global coroutines are like daemon threads)

(五)其他
1. Dispatchers

三. 實際操作coroutines:

(一)使用intellij時:
1.
必須建立Gradle專案,並將coroutines程式庫當成依賴項目加入build.gradle(如下圖,在dependencies{}加入kotlinx-coroutines-core)

(相關的處理方式可參閱:kotlinx.coroutines

(二) 使用AS時,
1. 在build.gradle(Module: app) 加入:
(1)kotlin{experimental{coroutines ‘enable’}}
(2)dependenices {implementation “
org.jetbrains.kotlinx:kotlinx-coroutines-android:0.27.0-eap13”}
2. 說明:
(1) kotlinx-coroutines-android→ for Android Main thread dispatcher
(2) '
0.27.0-eap13' 是版本,其他版本可以到kotlinx.coroutines’ library查詢

(三)承(一)(二),下一步就是import kotlinx.coroutines.*
說明:
kotlinx.coroutines is a rich library for coroutines developed by JetBrains. It contains a number of high-level coroutine-enabled primitives that this guide covers, including launch, async and others.

四. 補充: android studio 11發表會上提到的coroutines

從9分30秒開始介紹coroutines

五. 參考資料
(一)Book:
1. kotlin programming
2. 深入淺出kotlin

(二)官網
1. https://kotlinlang.org/docs/reference/coroutines-overview.html
2. https://kotlinlang.org/docs/reference/coroutines/basics.html
3. https://ktor.io/kotlinx/coroutines.html
4. https://developer.android.com/kotlin/coroutines
5. https://codelabs.developers.google.com/codelabs/kotlin-coroutines/index.html#3
6. youtobe: https://goo.gle/3gyiGDv

(三)個人
1. Roman Elizarov
2. Jast Lai: Kotlin Coroutine 幕後那一兩件事
3. abc: 鐵人賽
4. AndroidDevs: Starting our First Coroutine — Kotlin Coroutines

(四)其他
1. kotlinx.coroutines' library

六. 筆者溫馨小提醒:
1. 本文尚未完成(目前還在奮鬥中...),但由於目標之一是為了在導讀當天用來幫助讀書會成員了解本章節的輔助文章,因此先發布文章,若有引用到不恰當的地方(或是內容有錯誤),再麻煩告知,感謝!

2. GDG目前正在舉辦android 11的相關活動,有興趣者請參閱:Android 11 Meetups

3. 讀書會第一梯次在今天結束,若對kotlin有興趣,第二梯次的相關資訊可以進群組詢問喔!

--

--