Kotlin 使用協程編寫高效的併發程序

概念:

輕量級的線程

協程允許我們在單線程模式下模擬多線程編程的效果,代碼執行時的掛起與恢復完
全是由編程語言來控制的,和操作系統無關。這種特性使得高併發程序的運行效率得到了極大的提升。

依賴庫:

dependencies {
...
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.1.1"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.1.1"
}
fun main() {
GlobalScope.launch {
println("codes run in coroutine scope")
}
Thread.sleep(1000)
}

藉助runBlocking函數實現在協程中所有代碼執行完後再結束:

fun main() {
runBlocking {
println("codes run in coroutine scope")
delay(1500)
println("codes run in coroutine scope finished")
}
}

多個協程

子協程的特點是如果外層作用域的協程結束了,該作用域下的所有子協程也會一同結束。相比而言,GlobalScope.launch函數創建的永遠是頂層協程,這一點和線程比較像,因爲線程也沒有層級這一說,永遠都是頂層的。

fun main() {
    runBlocking {
        launch {
        println("launch1")
        delay(1000)
        println("launch1 finished")
    }
    launch {
        println("launch2")
        delay(1000)
        println("launch2 finished")
        }
    }
}

suspend掛起函數關鍵字

suspend關鍵字只能將一個函數聲明成掛起函數,是無法給它提供協程作用域的。

suspend fun printDot() {
    println(".")
    delay(1000)
}

coroutineScope掛起函數

coroutineScope函數和runBlocking函數還有點類似,它可以保證其作用域內的所
有代碼和子協程在全部執行完之前,外部的協程會一直被掛起。

suspend fun printDot() = coroutineScope {
    launch {
        println(".")
        delay(1000)
    }
}

fun main() {
    //協程作用域
    runBlocking {
        //子協程
        coroutineScope {
            launch {
                for (i in 1..10) {
                    println(i)
                    delay(1000)
                }
            }
        }
        println("coroutineScope finished")
    }
    println("runBlocking finished")
}

coroutineScope和runBlocking的區別

coroutineScope函數只會阻塞當前協程,既不影響其他協程,也不影響任何線程,因此是不
會造成任何性能上的問題的。

runBlocking函數由於會掛起外部線程,如果你恰好又在主線程中當中調用它的話,那麼就有可能會導致界面卡死的情況,所以不?推薦在實際項目中使用。

實際項目中協程的使用

val job = Job()
val scope = CoroutineScope(job)
scope.launch {
	// 處理具體的邏輯
}
//取消協程
job.cancel()

async函數 創建協程並獲取執行結果

async函數必須在協程作用域當中才能調用,它會創建一個新的子協程並返回一個Deferred對
象,如果我們想要獲取async函數代碼塊的執行結果,只需要調用Deferred對象的await()方法即可

fun main() {
    runBlocking {
        val start = System.currentTimeMillis()
        val deferred1 = async {
            delay(1000)
            5 + 5
        }
        val deferred2 = async {
            delay(1000)
            4 + 6
        }
        //兩個async函數同時執行,執行完後調用await()獲取結果
        println("result is ${deferred1.await() + deferred2.await()}.")
        val end = System.currentTimeMillis()
        println("cost ${end - start} milliseconds.")
    }
}

withContext()函數

簡化版的async函數

線程參數

Dispatchers.Default:表示會使用一種默認低併發的線程策略,當你要執行的代碼屬於計算密集型任務時,開啓過高的併發?而可能會影響任務的運行效率。

Dispatchers.IO:表示會使用一種較高併發的線程策略,當你要執行的代碼大多數時間是在阻塞和等待中,比如說執行網絡請求時,爲了能夠支持更高的併發數量。
Dispatchers.Main:不會開啓子線程,而是在Android主線程中執行代碼,但是這個值只能在Android項目中使用,純Kotlin程序使用這種類型的線程參數會出現錯誤。

fun main() {
    runBlocking {
        val result = withContext(Dispatchers.Default) {
        5 + 5
    }
    println(result)
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章