Kotlin-協(xié)程

一、開啟協(xié)程的方式

  1. 使用 runBlocking 頂層函數(shù)。它會 在協(xié)程作用域內(nèi)的所有代碼和子協(xié)程沒有全部執(zhí)行完成之前 一直阻塞當(dāng)前線程。一般在測試環(huán)境中使用。
runBlocking { 
}
  1. 使用 GlobalScope 單例對象。也是頂層協(xié)程。不推薦使用。
GlobalScope.launch {
}
  1. 創(chuàng)建 CoroutineScope 對象。CoroutineScope()是一個(gè)函數(shù),會返回一個(gè)CoroutineScope對象。之后調(diào)用它的launch函數(shù)就可以創(chuàng)建一個(gè)協(xié)程。
CoroutineScope(Dispatchers.XX).launch {
}
  1. launch,會在協(xié)程域中再開子協(xié)程。
runBlocking {
    launch {  }
}
  1. async方式,會在協(xié)程域中再開子協(xié)程。返回值是一個(gè)實(shí)現(xiàn)了Job接口的Dererred對象。
runBlocking {
    async {
    }
}

asnyc會返回一個(gè)Dererred對象。如果想要獲得async函數(shù)代碼塊的運(yùn)行結(jié)果,可以調(diào)用Dererred的await()方法。

runBlocking {
    val deferred = async {
    1+1
    }
    println(deferred.await())
}

await()方法會阻塞當(dāng)前協(xié)程,直到獲取到async函數(shù)的結(jié)果。

二、Dispatchers指定線程

  1. Dispatchers.Main:Android 中的主線程
  2. Dispatchers.IO:針對磁盤和網(wǎng)絡(luò) IO 進(jìn)行了優(yōu)化,適合 IO 密集型的任務(wù),比如:讀寫文件,操作數(shù)據(jù)庫以及網(wǎng)絡(luò)請求
  3. Dispatchers.Default:適合 CPU 密集型的任務(wù),比如計(jì)算
  4. Dispatchers.Unconfined:不推薦使用
runBlocking {
    withContext(Dispatchers.Main){
    }
    withContext(Dispatchers.IO){
    }
    withContext(Dispatchers.Default){
    }
}

三、suspend 關(guān)鍵字修飾的函數(shù)

表示該函數(shù)需要在協(xié)程中調(diào)用。

private suspend fun test(string:String) {
    println(string)
}

private suspend fun test(string:String) = withContext(Dispatchers.IO){
}

private suspend fun test(string:String) :String = withContext(Dispatchers.IO){
    "xxx"
}

協(xié)程代碼塊中代碼運(yùn)行到suspend函數(shù)時(shí),會暫時(shí)不再執(zhí)行剩余的協(xié)程代碼,而是先執(zhí)行完suspend函數(shù)再繼續(xù)往下執(zhí)行。

fun main(arg: Array<String>) {
    CoroutineScope(Dispatchers.Default).launch {
        println("1")
        test() // 運(yùn)行到suspend函數(shù),會執(zhí)行完suspend函數(shù)之后再往下執(zhí)行
        println("2")
    }
    Thread.sleep(6000)
    println("end")
}

suspend fun test() {
    delay(3000)
    println("test")
}

運(yùn)行結(jié)果
1
test
2
end

四、子協(xié)程launch代碼塊

子協(xié)程launch代碼塊不會影響后面代碼的運(yùn)行(因?yàn)樽訁f(xié)程本來就是新的協(xié)程,和原來的代碼塊分開各跑各的)。

fun main(arg: Array<String>) {
    CoroutineScope(Dispatchers.Default).launch {
        launch { // 新的子協(xié)程,不影響后面代碼的運(yùn)行
            delay(3000)
            println("0")
        }
        test()
        println("1")
    }
    Thread.sleep(6000)
    println("end")
}

suspend fun test() {
    delay(1000)
    println("test")
}

運(yùn)行結(jié)果
test
1
0
end

六、coroutineScope函數(shù)和CoroutineScope函數(shù)的區(qū)別。

  1. coroutineScope函數(shù)是一個(gè)由suspend修飾的掛起函數(shù),需要在協(xié)程作用域中被調(diào)用。也可以在其它掛起函數(shù)中調(diào)用。coroutineScope{}中的代碼執(zhí)行完之前,一直阻塞外部協(xié)程(因?yàn)樗菕炱鸷瘮?shù))。
fun main() {
    runBlocking { // runBlocking阻塞了外部線程
        coroutineScope{
            // coroutineScope阻塞了runBlocking協(xié)程
            launch {
                for (i in 1..10) {
                    println(i)
                    delay(1000)
                }
            }
        }
        println("runBlocking last line.")
    }
    println("main finished.")
}

運(yùn)行結(jié)果:

1
2
3
4
5
6
7
8
9
10
runBlocking last line.
main finished.
  1. CoroutineScope()是一個(gè)函數(shù),會返回一個(gè)CoroutineScope對象。之后調(diào)用它的launch函數(shù)就可以創(chuàng)建一個(gè)協(xié)程。不會阻塞外部線程、協(xié)程。
fun main() {
    runBlocking {
        CoroutineScope(Dispatchers.Default).launch{
            for (i in 1..10) {
                println(i)
                delay(1000)
            }
        }
        println("runBlocking last line.")
    }
    println("main finished.")
}

運(yùn)行結(jié)果:
既沒有阻塞外部線程也沒有阻塞外部協(xié)程。

runBlocking last line.
1
main finished.
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容