協(xié)程(Coroutine)是一種程序組件,它可以在執(zhí)行過(guò)程中掛起和恢復(fù),而不需要顯式地創(chuàng)建和管理線程。協(xié)程由三部分組成:協(xié)程體(Coroutine Body),協(xié)程構(gòu)造器(Coroutine Constructor)和協(xié)程掛起函數(shù)(Suspend Function)。?
?協(xié)程 CoroutineScope (協(xié)程作用域) 的上下文中通過(guò) launch、async 等構(gòu)造器來(lái)啟動(dòng)。GlobalScope ,即全局作用域內(nèi)啟動(dòng)了一個(gè)新的協(xié)程,這意味這該協(xié)程的生命周期只受整個(gè)應(yīng)用程序的生命周期的,即只要整個(gè)應(yīng)用程序還在運(yùn)行中,只要協(xié)程的任務(wù)還未結(jié)束,該協(xié)程就可以一直運(yùn)行。 // launch 代碼塊默認(rèn)運(yùn)行于線程池中
//在后臺(tái)啟動(dòng)一個(gè)新協(xié)程
GlobalScope.launch {
delay(1000)//非阻塞式延遲
println("World!")
}
println("Hello ")
?runBlocking函數(shù)同樣會(huì)創(chuàng)建一個(gè)協(xié)程的作用域,但是它可以保證在協(xié)程作用域內(nèi)的所有代碼和子協(xié)程沒(méi)有全部執(zhí)行完之前一直阻塞當(dāng)前線程。需要注意的是,runBlocking函數(shù)通常只應(yīng)該在測(cè)試環(huán)境下使用,在正式環(huán)境中使用容易產(chǎn)生一些性能上的問(wèn)題。// runblocking 運(yùn)行 main 線程
除了使用官方的幾個(gè)協(xié)程構(gòu)建器之外,還可以使用 coroutineScope 來(lái)聲明自己的作用域。 coroutineScope 用于創(chuàng)建一個(gè)協(xié)程作用域,直到所有啟動(dòng)的子協(xié)程都完成后才結(jié)束。
RunBlocking 和 coroutineScope 看起來(lái)很像,因?yàn)樗鼈兌际切枰却渌鼉?nèi)部所有相同作用域的子協(xié)程結(jié)束后才會(huì)結(jié)束自己。兩者的主要區(qū)別在于 runBlocking 方法會(huì)阻塞當(dāng)前線程,而 coroutineScope 只是掛起并釋放底層底層線程以供其他協(xié)程使用。由于這個(gè)差別,所以 runBlocking 是一個(gè)普通函數(shù),而 coroutineScope 是一個(gè)掛起函數(shù)。
runBlocking {
//非阻塞 GlobalScope
launch {
delay(200)
println("Task from runBlocking")
}
//非阻塞
coroutineScope {
launch {
delay(500)
println("Task from nested launch")
}
delay(100)
println("Task from coroutine scope")
}
println("Coroutine scope is over")
}
??suspend 掛起函數(shù)可以想常規(guī)函數(shù)一樣在協(xié)程中使用,但是它們的額外特性是:可以依次使用其他掛起函數(shù)(如delay函數(shù))來(lái)使協(xié)程掛起。
suspend fun doWorld() {
delay(1000)
println("World!")
}
suspend關(guān)鍵字只能將一個(gè)函數(shù)聲明成掛起函數(shù),是無(wú)法給它提供協(xié)程作用域的。比如你現(xiàn)在嘗試在doWorld()函數(shù)中調(diào)用launch函數(shù),一定是無(wú)法調(diào)用成功的,因?yàn)閘aunch函數(shù)要求必須在協(xié)程作用域當(dāng)中才能調(diào)用
這個(gè)問(wèn)題可以借助coroutineScope函數(shù)來(lái)解決。coroutineScope函數(shù)也是一個(gè)掛起函數(shù),因此可以在任何其他掛起函數(shù)中調(diào)用。它的特點(diǎn)是會(huì)繼承外部的協(xié)程的作用域并創(chuàng)建一個(gè)子協(xié)程,借助這個(gè)特性,我們就可以給任意掛起函數(shù)提供協(xié)程作用域了。
suspend fun doWorld() = coroutineScope{
launch {
println(".")
delay(1000)
}
}
總結(jié)看上去coroutineScope函數(shù)和runBlocking函數(shù)的作用是有點(diǎn)類(lèi)似的,但是coroutineScope函數(shù)只會(huì)阻塞當(dāng)前協(xié)程,既不影響其他協(xié)程,也不影響任何線程,因此是不會(huì)造成任何性能上的問(wèn)題的。而runBlocking函數(shù)由于會(huì)掛起外部線程,如果你恰好又在主線程中當(dāng)中調(diào)用它的話,那么就有可能會(huì)導(dǎo)致界面卡死的情況,所以不太推薦在實(shí)際項(xiàng)目中使用。?
GlobalScope.launch、runBlocking、launch、coroutineScope這幾種作用域構(gòu)建器,它們都可以用于創(chuàng)建一個(gè)新的協(xié)程作用域。不過(guò)GlobalScope.launch和runBlocking函數(shù)是可以在任意地方調(diào)用的,coroutineScope函數(shù)可以在協(xié)程作用域或掛起函數(shù)中調(diào)用,而launch函數(shù)只能在協(xié)程作用域中調(diào)用。
runBlocking由于會(huì)阻塞線程,因此只建議在測(cè)試環(huán)境下使用。而GlobalScope.launch由于每次創(chuàng)建的都是頂層協(xié)程,一般也不太建議使用,除非你非常明確就是要?jiǎng)?chuàng)建頂層協(xié)程。因此,GlobalScope.launch這種協(xié)程作用域構(gòu)建器,在實(shí)際項(xiàng)目中也是不太常用的。下面我來(lái)演示一下實(shí)際項(xiàng)目中比較常用的寫(xiě)法:
val job = Job()
val scope = CoroutineScope(job)
scope.launch {
//處理具體邏輯
}
job.cancel()
可以看到,我們先創(chuàng)建了一個(gè)Job對(duì)象,然后把它傳入CoroutineScope()函數(shù)當(dāng)中,注意這里的CoroutineScope()是個(gè)函數(shù),雖然它的命名更像是一個(gè)類(lèi)。CoroutineScope()函數(shù)會(huì)返回一個(gè)CoroutineScope對(duì)象,這種語(yǔ)法結(jié)構(gòu)的設(shè)計(jì)更像是我們創(chuàng)建了一個(gè)CoroutineScope的實(shí)例,可能也是Kotlin有意為之的。有了CoroutineScope對(duì)象之后,就可以隨時(shí)調(diào)用它的launch函數(shù)來(lái)創(chuàng)建一個(gè)協(xié)程了。
現(xiàn)在所有調(diào)用CoroutineScope的launch函數(shù)所創(chuàng)建的協(xié)程,都會(huì)被關(guān)聯(lián)在Job對(duì)象的作用域下面。這樣只需要調(diào)用一次cancel()方法,就可以將同一作用域內(nèi)的所有協(xié)程全部取消,從而大大降低了協(xié)程管理的成本。
因篇幅問(wèn)題不能全部顯示,請(qǐng)點(diǎn)此查看更多更全內(nèi)容
Copyright ? 2019- 91gzw.com 版權(quán)所有 湘ICP備2023023988號(hào)-2
違法及侵權(quán)請(qǐng)聯(lián)系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市萬(wàn)商天勤律師事務(wù)所王興未律師提供法律服務(wù)