Kotlin coroutines cheat sheet

Coroutines

CoroutineScope

協程做用域,任何協程都必須運行在 CoroutineScope 中。html

  • GlobalScope:全局做用域,非結構化併發,持有 EmptyCoroutineContext
  • runBlocking:全局做用域,通常用於 main() 或測試中,會阻塞當前線程。
  • coroutineScope:局部做用域,結構化併發,當全部子協程執行完畢纔會返回,而且等待過程當中不會阻塞當前線程;其中一個子協程發生異常,全部其餘子協程都會取消。
  • supervisorScope:局部做用域,結構化併發,當全部子協程執行完畢纔會返回,而且等待過程當中不會阻塞當前線程;其中一個子協程發生異常,不會影響其它子協程。
  • viewModelScope:Android ktx 提供的用於 ViewModel 中啓動協程的做用域,結構化併發,會在 ViewModel#clear() 中自動取消。
  • CoroutineScope:能夠本身實現該接口,實現自定義做用域。內部有個 CoroutineContext 屬性。

Coroutine builders

  • launch:建立一個不會阻塞當前線程的新協程,並返回給該協程一個 Job 引用。
  • runBlocking:建立一個新協程,該協程執行完畢前會阻塞當前線程,並返回協程執行結果。
  • async:建立一個不會阻塞當前線程的新協程,並返回協程執行結果類型的 Deferred 對象。
  • withContext:改變當前協程的 CoroutineContext,通常配合 Dispatchers 使用。

Coroutine context

協程運行的上下文,以鍵值對的方式存儲各類不一樣元素。git

  • EmptyCoroutineContext:空實現,不會改變協程的行爲,相似空 Map。
  • CoroutineName:爲了便於調試可設置協程名稱。
  • Job:協程的生命週期,可用於取消協程。協程與其子協程經過 Job 聯繫在一塊兒,它會等待全部子協程都執行完畢,並在其中一個發生異常時取消全部的子協程(想要各個子協程不相互影響可使用 SupervisorJob)。取消父協程的 Job 會取消該父協程的全部子協程 Job;其中一個子協程執行失敗或拋出 CancellationException 也會致使父協程被取消。
  • CoroutineExceptionHandler:處理協程內部未被捕獲的異常。
  • ContinuationInterceptor:協程恢復攔截器,主要在 dispatchers 中使用。

Coroutine dispatchers

協程調度器,有如下幾種實現:github

  • Dispatchers.Default:每次都切換到線程池的一個不一樣線程,通常用於 CPU 密集型任務。
  • Dispatchers.Main:平臺相關的主線程,默認不可用,須要在各自平臺實現。
  • Dispatchers.IO:用於執行一些阻塞的 IO 操做,如網絡請求、數據庫讀寫,文件操做等。
  • Dispatchers.Unconfined:老是使用第一個可用線程,具備不肯定性,性能最優。
  • newSingleThreadContext:實驗性,使用一個單線程建立新的協程上下文。
  • newFixedThreadPoolContext:實驗性,使用一個指定大小的線程池建立新的協程上下文。

Channels

通道,相似 BlockingQueue,提供非阻塞的 send()receive,可實現生產者--消費者模型。能夠關閉通道。數據庫

  • 扇出(Fan-out):多個協程也許會接收相同的通道,在它們之間進行分佈式工做。
  • 扇入(Fan-in):多個協程能夠發送到同一個通道。
fun CoroutineScope.produceSquares(): ReceiveChannel<Int> = produce {
    for (x in 1..5) send(x * x)
}

val squares = produceSquares()
squares.consumeEach { println(it) } //1, 4, 9, 16, 25
複製代碼

Sequence builder

val childNumbers = sequence {
  yield(1)
  print("AAA")
  yieldAll(listOf(2, 3))
}
childNumbers.forEach { print(it) } //1AAA23

val nums = childNumbers.joinToString() // AAA
print(nums) // 1, 2, 3
複製代碼

Deal with shared state

共享的可變狀態與併發。安全

  • AtomicInteger:可以使用原子基本類型。線程安全的。
  • AtomicReference<V>:可以使用原子引用類型。線程安全的。
  • newSingleThreadContext:使用單線程模型。
  • Mutex:互斥,相似 synchronizedReentranLock。給關鍵代碼塊加鎖,確保不會被同時執行。
private val mutex = Mutex()
mutex.withLock { /**/ } 複製代碼

Actors

actor 協程構建器是一個雙重的 produce 協程構建器。一個 actor 與它接收消息的通道相關聯,而一個 producer 與它發送元素的通道相關聯。 在高負載下比鎖更有效,由於在這種狀況下它老是有工做要作,並且根本不須要切換到不一樣的上下文。網絡

// 計數器 Actor 的各類類型
sealed class CounterMsg
object IncCounter : CounterMsg() // 遞增計數器的單向消息
object PrintCounter : CounterMsg() // 打印的單向消息
class GetCounter(val response: CompletableDeferred<Int>) : CounterMsg() // 攜帶回復的請求

// 這個函數啓動一個新的計數器 actor
fun CoroutineScope.counterActor() = actor<CounterMsg> {
    var counter = 0 // actor 狀態
    for (msg in channel) { // 即將到來消息的迭代器
        when (msg) {
            is IncCounter -> counter++
            is PrintCounter -> print(counter)
            is GetCounter -> msg.response.complete(counter)
        }
    }
}
複製代碼

Reference

聯繫

我是 xiaobailong24,您能夠經過如下平臺找到我:併發