launch與async:Kotlin協程中的即興與精準控制
想象你正在準備周末的家庭聚餐:水槽里堆著要洗的蔬菜,電飯煲指示燈在閃爍,平底鍋里的牛排正滋滋作響...這時候你突然意識到—這不就是協程的完美應用場景嗎?
launch():料理界的獨行俠
假設你想同時煮飯和煎牛排,但根本不關心牛排煎到幾分熟,這時候就該請出launch()
這位瀟灑的大廚:
fun prepareDinner() = runBlocking {
// 啟動兩個火灶
val riceJob = launch { cookRice() }
val steakJob = launch { panFrySteak() }
// 趁這個時間做杯咖啡
brewCoffee()
// 最后確認所有操作完成
joinAll(riceJob, steakJob)
}
suspend fun cookRice() {
println("?? 米粒開始溫泉之旅...")
delay(20000)
println("?? 米飯變身成功!")
}
suspend fun panFrySteak() {
println("?? 牛排跳進熱舞池...")
delay(15000)
println("?? 牛排完成桑拿浴!")
}
suspend fun brewCoffee() {
println("? 咖啡機開始打太極...")
delay(5000)
println("? 手沖咖啡完成!")
}
運行結果:
? 咖啡機開始打太極...
?? 米粒開始溫泉之旅...
?? 牛排跳進熱舞池...
? 手沖咖啡完成!
?? 牛排完成桑拿浴!
?? 米飯變身成功!
?? 廚房哲學:就像你不會盯著電飯煲等飯熟,launch()
適合那些"點火后就不用管"的操作。比如:
? 后臺上傳日志文件
? 播放界面過渡動畫
? 發送用戶行為統計
async():料理界的控制狂
現在你要做海鮮燴飯,必須等蝦仁炒好、米飯煮熟才能混合,這時候async()
就是你的最佳搭檔:
fun makePaella() = runBlocking {
// 啟動兩個精密計時器
val riceDeferred = async { cookRice() }
val shrimpDeferred = async { sauteShrimp() }
// 準備其他食材
chopVegetables()
// 等待所有材料就緒
val rice = riceDeferred.await() // 等待米飯
val shrimp = shrimpDeferred.await() // 等待蝦仁
mixIngredients(rice, shrimp)
}
suspend fun sauteShrimp(): String {
println("?? 蝦仁跳進橄欖油泳池...")
delay(12000)
println("?? 蝦仁穿上了金甲圣衣!")
return "香煎蝦仁"
}
suspend fun chopVegetables() {
println("?? 菜刀演奏廚房交響曲...")
delay(8000)
println("?? 蔬菜變身精致小方塊")
}
fun mixIngredients(rice: String, shrimp: String) {
println("?? 把「$rice」和「$shrimp」放入魔法坩堝...")
println("? 海鮮燴飯大功告成!")
}
運行結果:
?? 菜刀演奏廚房交響曲...
?? 蝦仁跳進橄欖油泳池...
?? 米粒開始溫泉之旅...
?? 蔬菜變身精致小方塊
?? 米飯變身成功!
?? 蝦仁穿上了金甲圣衣!
?? 把「香糯米飯」和「香煎蝦仁」放入魔法坩堝...
? 海鮮燴飯大功告成!
?? 黃金法則:當后續步驟需要依賴前序結果時,請使用async()/await()
組合拳:
? 同時請求多個API接口
? 并行計算數據報表
? 多任務文件下載
協程雙雄對比表
對比維度 | launch() | async() |
返回值 | 工作簽證(Job) | 承諾書(Deferred) |
結果處理 | 做完就算,不問結果 | 必須出示完成憑證 |
異常處理 | 立即引發廚房警報 | 把問題藏在圍裙里直到你檢查 |
適用場景 | 燒水、預熱烤箱等后臺雜務 | 需要精確配合的工序 |
代碼特征 | 點火后轉身就走 | 必須收到完成回執 |
高級料理技巧
異常處理就像滅火器
val job = launch {
try {
riskyCooking()
} catch (e: BurnException) {
println("?? 觸發煙霧報警!原因:${e.message}")
}
}
val deferred = async {
dangerousChopping()
}
deferred.invokeOnCompletion { cause ->
cause?.let {
println("?? 刀工表演出事故:${it.message}")
}
}
協程調度器就像灶臺選擇
// 使用IO灶臺處理網絡請求
launch(Dispatchers.IO) { fetchRecipe() }
// 使用主灶臺更新UI
launch(Dispatchers.Main) { updateProgressBar() }
// 創建專屬料理臺
val privateKitchen = newSingleThreadContext("私人廚房")
編程如烹飪,火候見真章,好的代碼和好的料理一樣,都需要掌握并行處理的精髓。下次當你在代碼中敲下launch
或async
時,記住這不僅僅是語法選擇——這是你在并發世界的生存策略。就像廚師要同時掌握猛火快炒和文火慢燉,真正的協程高手懂得什么時候該放手,什么時候必須較真。