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
John Lu

Written by 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.