launch vs async

神奇的 Coroutines [2]

John Lu
4 min readJan 11, 2023

可以透過下列任一方式啟動 coroutines:

  • launch 會啟動新的 coroutine,但不會傳回結果給呼叫端。任何視為「射後不理」的工作都可以使用 launch 啟動。
  • async 會啟動新的 coroutine,並透過 await 這個 suspend function 回傳結果。

筆記:

  • 通常從一般函式去 launch 一個新的 coroutine。
  • async只能使用在 coroutine 裡面,或在 suspend function 裡面執行 parallel decomposition 時。
  • 一般函式無法呼叫 await

注意: launchasync 處理 exception 的方式不同。由於 async 預期最終會呼叫 await,所以它會先將 exception 保留,並在呼叫 await 時 throw exception。這意味著,如果使用 async,從一般函式啟動新的 coroutine,則可能會自動捨棄 exception。這些遭捨棄的 exception 不會顯示在 crash metrics,也不會記錄在 logcat。詳情可以參考下面這篇文章。

Parallel decomposition

所有在 suspend function 裡啟動的 coroutine,都必須在函式傳回時停止,因此可能需要確保,這些 coroutine 要在 function 傳回前執行完畢。我們可以運用 coroutine「structured concurrency」的特性,定義 coroutineScope 來啟動一個或多個 coroutine。然後,使用 await() (針對一個 coroutine) 或 awaitAll() (針對多個 coroutine),就可確保這些 coroutine 在從函式傳回之前執行完畢。

例如,這邊定義一個 coroutineScope以非同步方式來擷取兩份文件。對每個 deferred reference 呼叫 await(),就能確保兩項 async 作業都會在 function 傳回之前執行完畢:

suspend fun fetchTwoDocs() =
coroutineScope {
val deferredOne = async { fetchDoc(1) }
val deferredTwo = async { fetchDoc(2) }
deferredOne.await()
deferredTwo.await()
}

另外也可以在 collections 上使用 awaitAll(),如下所示:

suspend fun fetchTwoDocs() =        // called on any Dispatcher (any thread, possibly Main)
coroutineScope {
val deferreds = listOf( // fetch two docs at the same time
async { fetchDoc(1) }, // async returns a result for the first doc
async { fetchDoc(2) } // async returns a result for the second doc
)
deferreds.awaitAll() // use awaitAll to wait for both network requests
}

使用 awaitAll() 會讓 fetchTwoDocs()函式等待 async 啟動的 coroutines 執行完畢,然後才會回傳。不過要注意,如果沒有呼叫 awaitAll()coroutineScope builder 不會繼續執行呼叫 fetchTwoDocs 的 coroutine,直到所有使用 async 啟動的 coroutine 執行完畢為止。

此外,coroutineScope 會 catch 所有 coroutine 丟出的 exceptions,並轉送至呼叫端。

如要進一步瞭解 parallel decomposition,可參考下面這篇文章。

https://kotlinlang.org/docs/reference/coroutines/composing-suspending-functions.html

--

--

John Lu

AI Engineer. Deeply motivated by challenges and tends to be excited by breaking conventional ways of thinking and doing. He builds fun and creative apps.