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