Kotlin雜談(五) - Coroutines(三): 基本語法
(圖id: 63459694 (pixiv)
這次偷懶的時間比較久...(GBF這種大農場啊,費時,而且在寫JavaFX WIKI爬蟲軟體的UI,UI這種東西啊,燒腦,能不寫就不寫,反正我就是沒啥UI感,抄也不滿意)
回歸基本步,說一下kotlin coroutine的基本語法首先是launch,這是最常見最簡單的coroutine builder,語法如下
fun fuck() {n launch(CommonPool) { //建立協程,CommonPool為預設協程池n delay(1000L) //in msn println("Fuck")n }n}n
不太理解這段是在做啥的可以這樣想
launch(CommonPool) {} <-> thread {}
delay() <-> Thread.sleep()
但你絕對不能在thread中使用delay, 因為delay是suspending function, suspend function的運行背景必需是coroutine, 而thread不是coroutine, 所以會報錯
為甚麽呢?因為suspending function執行時會掛起當前的subroutine, thread可沒有掛起這種方便的功能...(我知道有人會想說wait/notify, 但那嚴格來說是屬於object的, 而且掛起subroutine的資源消耗更低)
然後官方為了方便大家在coroutine區分阻塞與非阻塞代碼,而且減少使用Thread這種胖子,就推薦了以下的寫法
fun fuck() = runBlocking<Unit> { //<Unit>可略, 開始主協程n launch(CommonPool) {n delay(1000L) //in msn println("Bitch")n }n println("Fuck,")n delay(2000L) //2秒後函數才會完成n}nn//結果nFuck,nBitchn
runBlocking為最高級的協程 (一般為主協程), 其他協程如launch {} 能跑在runBlocking (因為層級較低), 反過來卻不行, 文檔有推薦利用這特性寫測試...代碼就不上了, JUnit而已
嗯,有一些有用過Thread的人大概會問"我想要阻塞特定協程,有沒有方法?", 有, 而且跟Thread一樣,上代碼
fun main(args: Array<String>) = runBlocking {n val job = launch(CommonPool) { //這貨返回的是Job,跟Runnable類似n delay(1000L)n println("bitch")n }n println("Fuck,")njob.join()n}n
就這麽簡單, 甚麽你問能不能cancel? 當然可以了...詳細可以爬Job的源碼, 另外文檔說: 所有kotlinx.coroutines裡面的suspend fun都是可被取消的, 其原理是cancel時會拋出CancellationException, 然後isActive會被賦值為False, 只有你的suspend fun有檢查isActive屬性才有被取消的能力 (另一個方法是用yield)
提醒一點,如果想在協程內呼叫具有suspending能力的函數,該函數必須宣告suspend,如下
suspend fun fuck() {loop { delay(1000L) }}n
協程的生命周期問題...看下面代碼
fun main(args: Array<String>) = runBlocking<Unit> {n launch(CommonPool) {n repeat(1000) { i ->n println("Im sleeping $i ...")n delay(500L)n }n }n delay(1300L) // delay 1.3秒後直接把程序結束n}n//能跑3次,print $0/$1/$2n
至於協程的資源管理嘛, 老牌的try..finally, 或者實作了Closeable的class呼叫use函數, 這是RAII, use執行完成後class自動析構
如果用try..finally時, finally一般會進行資源析構的動作, 這些代碼必須保證被執行, 然而finally的代碼是能被cancel的...為了防止不應該被cancel的代碼受影響,Koltin提供了不能取消的協程fun fuck() = runBlocking {n try {n } finally {nrun(NonCancellable) {n println("hi")n }n }n}n
協程也支援設定時限...畢竟非同步常用的場景是IO,超時這點算是必需品了
withTimeout(1300L) { //in ms, 1.3秒沒執行完直接停掉並拋出TimeoutExceptionn}n
今天就這麽多,基本語法沒很複雜
下一回講async/context/dispatcher, 等我古戰場進了A組回來寫(逃推薦閱讀: