Kotlin(十九)協(xié)程初探究<1>

Kotlin 的Coroutine

前面說(shuō)過(guò)傳統(tǒng)web框架Tomcat采用的多線程方式,當(dāng)請(qǐng)求接入服務(wù)器時(shí),Tomcat會(huì)為每個(gè)請(qǐng)求鏈接分配一個(gè)線程。當(dāng)請(qǐng)求不是很多的時(shí)候,系統(tǒng)不會(huì)出現(xiàn)問(wèn)題,請(qǐng)求數(shù)目超過(guò)最大分配線程數(shù),這個(gè)時(shí)候會(huì)有多個(gè)線程阻塞住,會(huì)出現(xiàn)一些問(wèn)題。

多線程在執(zhí)行的時(shí)候,知識(shí)看上去是同時(shí)執(zhí)行,因?yàn)榫€程執(zhí)行是通過(guò)cpu來(lái)進(jìn)行調(diào)度的,cpu通過(guò)在每個(gè)線程之間來(lái)回切換,使其看上去是同時(shí)執(zhí)行的一樣。其實(shí)cpu在某個(gè)時(shí)間片內(nèi)只能執(zhí)行一個(gè)線程,當(dāng)這個(gè)線程執(zhí)行一會(huì)它就會(huì)去執(zhí)行其他線程。當(dāng)cpu從一個(gè)線程切換到另一個(gè)線程時(shí)候會(huì)執(zhí)行如下操作:

  • 保存當(dāng)前執(zhí)行線程的執(zhí)行上下文
  • 載入另一個(gè)線程的執(zhí)行上下文

協(xié)程是一個(gè)無(wú)優(yōu)先級(jí)的調(diào)度組件,允許子程序在特定地方掛起恢復(fù)。
線程包含于進(jìn)程,協(xié)程包含于線程。
只要內(nèi)存夠用,一個(gè)線程中可以有任意多個(gè)協(xié)程,但某一時(shí)刻只能由一個(gè)協(xié)程運(yùn)行,多個(gè)協(xié)程該線程分配到的計(jì)算機(jī)資源。

fun main(args: Array<String>) {
    GlobalScope.launch { // 在后臺(tái)啟動(dòng)一個(gè)協(xié)程
        delay(1000L) // 延遲一秒(非阻塞)
        println("World!") // 延遲之后輸出
    }
    println("Hello,") // 協(xié)程被延遲了一秒,但是主線程繼續(xù)執(zhí)行
    Thread.sleep(2000L) // 為了使JVM?;?,阻塞主線程2秒鐘(這段代碼刪掉會(huì)出現(xiàn)什么情況???)
}

launch 構(gòu)造了一個(gè)協(xié)程,該協(xié)程內(nèi)部調(diào)用了delay方法,該方法會(huì)掛起協(xié)程,但是不會(huì)阻塞線程,所以在協(xié)程推遲1s的時(shí)間,線程中的“Hello”會(huì)先輸出,然后“World!”才會(huì)輸出

協(xié)程的切換可以通過(guò)程序自己控制,是工作在線程之上的,不需要操作系統(tǒng)調(diào)度,理論上降低了開銷。

1. launch 與 runBlocking

上面的例子只是為了說(shuō)明線程和協(xié)程理論的相似處,存在不合理的地方。我們既使用了delay方法,又使用了sleep方法。

  • delay 只能在協(xié)程中使用,用于掛起協(xié)程,不會(huì)阻塞線程。
  • sleep 用來(lái)阻塞線程
fun main(args: Array<String>) = runBlocking{
    launch { // 在后臺(tái)啟動(dòng)一個(gè)協(xié)程
        delay(1000L) // 延遲一秒(非阻塞)
        println("World!") // 延遲之后輸出
    }
    println("Hello,") // 協(xié)程被延遲了一秒,但是主線程繼續(xù)執(zhí)行
    Thread.sleep(2000L) // 為了使JVM?;睿枞骶€程2秒鐘(這段代碼刪掉會(huì)出現(xiàn)什么情況???)
}

這個(gè)例子和上面的基本沒(méi)有變化,結(jié)果也一樣,我們看到兩個(gè)函數(shù)
launch和runBlocking 這兩個(gè)函數(shù)都會(huì)啟動(dòng)一個(gè)協(xié)程,不同的是runBlocking啟動(dòng)一個(gè)主協(xié)程,launch啟動(dòng)的協(xié)程能在runBlocking中運(yùn)行(反過(guò)來(lái)不行)。runBlocking 方法仍舊會(huì)阻塞當(dāng)前執(zhí)行的線程。

2. 協(xié)程的生命周期與join

delay和sleep都是延遲執(zhí)行,目的都是?;畛绦?。
但是我們執(zhí)行IO操作的時(shí)候并不知道操作執(zhí)行多久,沒(méi)法設(shè)定一個(gè)時(shí)間讓程序?;睿瑸榱俗寘f(xié)程執(zhí)行完畢前一直?;?,我們可以使用join

fun main(args: Array<String>) = runBlocking {
    val job = launch {
        search()
    }
    println("Hello,")
    job.join()
}

suspend fun search() {
    delay(1000L)
    println("World!")
}

出現(xiàn)了一個(gè)新的關(guān)鍵詞suspend。用suspend的方法,和其他方法沒(méi)有大的區(qū)別,不同的是suspend方法內(nèi)部還可以調(diào)用其他suspend修飾的方法,只能在協(xié)程內(nèi)部或其他suspend方法中執(zhí)行,普通方法則不行。delay就是一個(gè)suspend修飾的方法。

fun main(args: Array<String>) = runBlocking<Unit> {
    val one = searchItemlOne()
    val two = searchItemTwo()
    println("The items is ${one} and ${two}")
}

fun main(args: Array<String>) = runBlocking<Unit> {
    val one = async { searchItemlOne() }
    val two = async { searchItemTwo() }
    println("The items is ${one.await()} and ${two.await()}")
}

再看下上面的例子,執(zhí)行結(jié)果是一樣的,第一個(gè)在協(xié)程內(nèi)部執(zhí)行是順序的,類似java中的同步,限執(zhí)行searchItemlOne在執(zhí)行searchItemTwo。為了讓兩個(gè)方法并行執(zhí)行,使用Kotlin中的async與await。async類似前面的launch都是創(chuàng)建了一個(gè)子協(xié)程,不同的是async有返回值,返回Deferred對(duì)象。

Deferred 是一個(gè)非阻塞可以取消的future,是一個(gè)帶有結(jié)果的job
launch 也會(huì)返回一個(gè)job對(duì)象,但是沒(méi)有返回值

我們還用到了await,future是非阻塞,意思將來(lái)會(huì)有一個(gè)結(jié)果返回。await可以等待這個(gè)值查詢到后,將它獲取出來(lái)。

fun main() = runBlocking{
    val time = measureTimeMillis {
        val one = searchItemlOne()
        val two = searchItemTwo()
        println("The items is ${one} and ${two}")
    }
    println("Cost time is ${time} ms")
}

The items is item-one and item-two
Cost time is 2034 ms

再看并行

fun main(args: Array<String>) = runBlocking{
    val time = measureTimeMillis {
        val one = async { searchItemlOne() }
        val two = async { searchItemTwo() }
        println("The items is ${one.await()} and ${two.await()}")
    }

    println("Cost time is ${time} ms")
}

The items is item-one and item-two
Cost time is 1170 ms

從理論代碼看不出差別,但是從時(shí)間打印來(lái)看,并行效果就明顯了。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請(qǐng)通過(guò)簡(jiǎn)信或評(píng)論聯(lián)系作者。

相關(guān)閱讀更多精彩內(nèi)容

  • 最近一直在了解關(guān)于 Kotlin協(xié)程 的知識(shí),那最好的學(xué)習(xí)資料自然是官方提供的學(xué)習(xí)文檔了,看了看后我就萌生了翻譯官...
    業(yè)志陳閱讀 1,212評(píng)論 0 1
  • kotlin這個(gè)夏天java最有競(jìng)爭(zhēng)力的語(yǔ)言。關(guān)于它的語(yǔ)法糖在這就不一一闡述了,畢竟它能甜死你。先說(shuō)說(shuō)什么是協(xié)程吧...
    null_zhou閱讀 4,126評(píng)論 3 7
  • [TOC] 簡(jiǎn)介 Coroutines are computer program components that ...
    Whyn閱讀 6,152評(píng)論 5 15
  • 在今年的三月份,我因?yàn)樾枰獮轫?xiàng)目搭建一個(gè)新的網(wǎng)絡(luò)請(qǐng)求框架開始接觸 Kotlin 協(xié)程。那時(shí)我司項(xiàng)目中同時(shí)存在著兩種...
    業(yè)志陳閱讀 1,216評(píng)論 0 5
  • 推薦指數(shù): 6.0 書籍主旨關(guān)鍵詞:特權(quán)、焦點(diǎn)、注意力、語(yǔ)言聯(lián)想、情景聯(lián)想 觀點(diǎn): 1.統(tǒng)計(jì)學(xué)現(xiàn)在叫數(shù)據(jù)分析,社會(huì)...
    Jenaral閱讀 5,950評(píng)論 0 5

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