Kotlin1.3 協程Api詳解:CoroutineScope, CoroutineContext

本篇文章解析Kotlin協程的CoroutineScope, CoroutineContext及其繼承類, 旨在探討並理解kotlin的協程使用,以及對各個協程api細節整理。html

關於協程跨平臺的實現以及跨平臺使用介紹,歡迎去個人博客:編譯以後--Kotlin 跨平臺協程看看,或者去看看官方的視頻&ppt,這也是我本篇文章的基礎:git

這篇文章好久前就已經打好了草稿,可是因爲最近忙沒有時間寫,再加上最近都沒有在寫Kotlin。今天仔細又讀了一些文檔、源碼,爲了整理一下本身的思路,將本身的我的理解寫在這裏。github

本文的前提是讀者瞭解協程基本使用,見官方中文文檔api

注:Kotlin版本迭代突飛猛進,本篇文章不免過期或有疏漏,請讀者注意。jvm

CoroutineScope

什麼是CoroutineScope? CoroutineScope能夠理解爲協程的做用域,能夠管理其域內的全部協程。一個CoroutineScope能夠有許多的子scope。async

建立子scope的方式有許多種,常見的有:ide

  • 使用lauch, async 等builder建立一個新的子協程。協程(AbstractCoroutine)繼承了 CoroutineScope,從父scope中繼承了協程上下文(見下文CoroutineContext) 以及Job(見下文)
  • 使用coroutineScope Api建立新scope: public suspend fun <R> coroutineScope(block: suspend CoroutineScope.() -> R): R 這個api主要用於方便地建立一個子域,而且管理域中的全部子協程。注意這個方法只有在全部 block中建立的子協程所有執行完畢後,纔會退出。以下示例:
    // print輸出的結果順序將會是 1, 2, 3, 4
          coroutineScope {
              delay(1000)
              println("1")
              launch { 
                  delay(6000) 
                  println("3")
              }
              println("2")
              return@coroutineScope
          }
          println("4")
    複製代碼
    與之相似的還有supervisorScope,區別是supervisorScope 在子協程失敗時不影響其餘子協程,而coroutineScope是將異常拋出。
  • 繼承CoroutineScope.這也是比較推薦的作法,用於處理具備生命週期的對象。
class SomethingWithLifecycle : CoroutineScope {

       // 建立一個Job,並用這個job來管理你的SomethingWithLifecycle的全部子協程
       private val job = Job()
       override val coroutineContext: CoroutineContext
            get() = Dispatchers.Main + job

       // 當生命週期銷燬時,結束全部子協程
       fun close() { job.cancel() }
}
複製代碼

CoroutineContext

這裏我將CoroutineContext翻譯爲協程上下文。 我也找不到更好的詞去翻譯它。協程上下文包含當前協程scope的信息, 好比的Job, ContinuationInterceptor, CoroutineName 和CoroutineId。在CoroutineContext中,是用map來存這些信息的, map的鍵是這些類的伴生對象,值是這些類的一個實例。 這個設計也是蠻騷的, 致使你能夠這樣子取得context的信息:ui

val job = context[Job]
val continuationInterceptor = context[ContinuationInterceptor]
複製代碼

每個信息(Element)的繼承關係大概是這樣的, 我拿Job來舉例:spa

Job.Key繼承了CoroutineContext.Key, Job 繼承了CoroutineContext.Element,而CoroutineContext.Element繼承了 CoroutineContext。.net

name 和 id都可有可無,咱們仔細講講Job和ContinuationInterceptor。

Job

如上文提到的,Job繼承了CoroutineContext.Element, 他是協程上下文的一部分。 Job有兩個重要的子類實現:JobSupport,提供Job 的父子關係管理, 和AbstractCoroutine,即協程。

Job對象持有全部的子job實例,能夠取消全部子job的運行。Job的join方法會等待本身以及全部子job的執行, 因此Job給予了CoroutineScope一個管理本身全部子協程的能力。

JobSupport

JobSupport這邊的api已經被標記爲廢棄了,未來可能會有變更。其實這邊api設計我感受有點看不懂,十分地confusing。之後看看有沒有變化吧,這部分主要是提供一個 工廠方法 Job(),能夠爲你的組件提供一個初始的context, 一個JobImpl的實例。JobSupport同時是AbstractCoroutine的父類。

AbstractCoroutine

講講Job最重要的子類: AbstractCoroutine。這個類就能夠直接理解爲是一個協程對象了,他繼承了CoroutineScope, Job, Continuation, JobSupport。

常見地, 使用launch 或者async方法都會實例化出一個AbstractCoroutine 的協程對象,而這個協程對象由於繼承了CoroutineScope,因此擁有一個協程上下文。 一個協程的協程上下文的Job值就是他自己,即:

val j = launch { delay(6000) }
            // True!
            println(j[Job] == j)
複製代碼

而關於Continuation,是kotlin內部用來跳轉恢復協程用的。這個東西對外部暴露的東西很少,咱們須要瞭解的有:

  • suspendCoroutine, 掛起當前協程,利用Continuation繼續協程的執行,經常使用於與其餘平臺阻塞方法兼容,這是1.1的api,很少作介紹
  • SequenceBuilderIterator,這個就是kotlin協程的生成器了,詳見官方文檔

ContinuationInterceptor

這個接口主要是由各類dispather實現。 見官方文檔 肚子好餓,不詳細介紹了,後面特別補上一篇文章細說dispatcher在各個平臺的表現吧, 敬請期待。

The end

最後推薦個神仙倉庫吧, kotlin的各類提案, 在這裏面能夠看到各類kotlin特性設計的方案。好比協程的:

github.com/Kotlin/KEEP…

若是以爲本篇文章對您有所幫助, 點個贊吧~~蟹蟹~

相關文章
相關標籤/搜索