coroutineScope , supervisorScope 和 launch ,async 的混合異常處理

特性

launchasync

  • launch :在協程內部馬上拋出異常,未捕獲的異常不會被保存, join 中也不會保存和傳遞異常,可是會接受由父協程傳遞過來的 JobCancellationException
  • async :不在協程內部馬上拋出異常,而將未捕獲的異常保存在生成的 Deferred 中,最後拋出時已經回到父協程了。

coroutineScopesupervisorScope

  • coroutineScope 內部的異常會向上傳播,子協程未捕獲的異常會向上傳遞給父協程,任何一個子協程異常退出,會致使總體的退出。
  • supervisorScope 內部的異常不會向上傳播,一個子協程異常退出,不會影響父協程和兄弟協程的運行。

示例

try {
    coroutineScope {
        try {
            val child1 = launch {
                log("Child1 is started")
                delay(100)
                throw ArithmeticException("Child1 error")
            }
			child1.join()
        } catch (e: Exception) {
            log("Child1: $e")
        }
        try {
            val child2 = launch {
                log("Child2 is started")
                delay(1000)
                log("Child2 is finished")
            }
            child2.join()
        } catch (e: Exception) {
            log("Child2: $e")
        }
    }
} catch (e: Exception) {
    log("Parent: $e")
}
複製代碼

切換外層的 coroutineScopesupervisorScope ,再對 child1 切換使用 launchasync ,最後獲得下表html

條件 child1 的 catch child 2 的 catch parent 的 catch
coroutineScope + launch JobCancellationException Child1 error
coroutineScope + launch + join JobCancellationException JobCancellationException Child1 error
coroutineScope + async JobCancellationException Child1 error
coroutineScope + async + await Child1 error JobCancellationException Child1 error
supervisorScope + launch JobCancellationException Child1 error
supervisorScope + launch + join Child1 error JobCancellationException Child1 error
supervisorScope + async
supervisorScope + async + await Child1 error

總結

launch 不管其父協程做用域是 coroutineScope 仍是 supervisorScope ,都會致使整個父協程做用域範圍內的協程的退出。而且由於 join 不會保存和傳播異常,即便 launch 自己在外部 try/catch 裏執行了 joincatch 中捕獲的也只是由父協程發出的取消。async

async 由於是將未捕獲的異常保存在生成的 Deferred 中,在父協程做用域是 coroutineScope 時,雖然一樣由於將異常拋給父協程致使整個父協程做用域範圍內的協程的退出。可是在外部 try/catch 裏執行 await 時, catch 也可以捕獲發生在 async 內部的異常。在父協程做用域是 supervisorScope 是,該 async 的崩潰不會影響兄弟協程和父協程其餘代碼的運行。spa

一般狀況下,使用經常使用的 coroutineScope + launch ,將異常捕獲寫在 launch 中就能夠了。.net

但在同時運行多個子協程時,有兩種狀況下,使用 supervisorScope + async 更爲便利。code

  1. 不能在協程內部調用 try/catch ,且一個協程的崩潰不能致使全部協程的退出
  2. 能夠在協程內部調用 try/catch ,可是對全部協程拋出的異常處理邏輯是相同的,且一個協程的崩潰應致使全部協程的退出

參考文章 :協程

Kotlin協程中的launch/join和async/await之間有什麼區別htm

異常處理作用域

Kotlin 協程(4) - 異常處理篇get

相關文章
相關標籤/搜索