Kotlin:協(xié)程 VS 傳統(tǒng)線程

結(jié)論

JVM平臺(tái),Kotlin語(yǔ)言使用多協(xié)程處理任務(wù)的效率并不優(yōu)于傳統(tǒng)多線程處理任務(wù)的效率。

背景

協(xié)程的概念很早就提出來(lái)了叽奥,先后已經(jīng)被Go俱两、Python等多個(gè)語(yǔ)言所支持饱狂。作為Android的第一開發(fā)語(yǔ)言,Kotlin官方也宣布支持了協(xié)程宪彩。但Kotlin的協(xié)程處理任務(wù)的效率真的高于傳統(tǒng)多線程嗎休讳?

方案

模擬一堆任務(wù),分別使用Kotlin多線程和Kotlin多協(xié)程并發(fā)處理這些任務(wù)尿孔,統(tǒng)計(jì)各自處理完成所有任務(wù)消耗的總時(shí)間俊柔,作為衡量效率高低的依據(jù)。本文的具體驗(yàn)證方案如下:

任務(wù)模擬:for循環(huán)中重復(fù)執(zhí)行除法運(yùn)算10G次作為一個(gè)任務(wù)

任務(wù)量模擬:20個(gè)模擬任務(wù)

多線程實(shí)現(xiàn):ThreadPoolExecutor + Callable + CountDownLatch活合,其中線程池的核心線程數(shù)為當(dāng)前硬件處理器最大核心數(shù)+1個(gè)雏婶,使用Callable是為了方便返回每一個(gè)任務(wù)具體耗時(shí),而CountDownLatch則是為了監(jiān)控是否所有的任務(wù)都已執(zhí)行完成白指。

多協(xié)程實(shí)現(xiàn):GlobalScope + Callable +?CountDownLatch留晚,使用默認(rèn)的Scope開啟協(xié)程,此處使用Callable只是為了方便統(tǒng)一兩個(gè)測(cè)試環(huán)境的數(shù)據(jù)源可以公用告嘲,而單純地在協(xié)程中調(diào)用了Callable的call()方法错维,CountDownLatch作用和多線程實(shí)現(xiàn)中的作用一致。

實(shí)施

硬件環(huán)境:

軟件環(huán)境:

IDEA:

JDK:

結(jié)果統(tǒng)計(jì)

數(shù)據(jù)分析

從上述數(shù)據(jù)可以看出Kotlin的多協(xié)程在執(zhí)行任務(wù)過(guò)程的效率并沒有傳統(tǒng)多線程優(yōu)秀橄唬,反而還有一點(diǎn)下降赋焕。從操作系統(tǒng)層面來(lái)講,協(xié)程確實(shí)是可以通過(guò)減少線程切換仰楚、上下文切換來(lái)提高效率隆判,而試驗(yàn)數(shù)據(jù)卻并不是預(yù)期的結(jié)果犬庇。這不得不讓人懷疑Kotlin的底層是否真的就實(shí)現(xiàn)了協(xié)程,還是說(shuō)僅僅只是基于線程的封裝蜜氨,類似于RxJava那種械筛。

其他

以上僅為個(gè)人理解,如有不足之處請(qǐng)諒解飒炎,您也可以留言指出埋哟。

完整代碼:

添加依賴:implementation"org.jetbrains.kotlinx:kotlinx-coroutines-core:1.2.1"

package com.xxxx

import kotlinx.coroutines.GlobalScope

import kotlinx.coroutines.launch

import java.util.concurrent.Callable

import java.util.concurrent.CountDownLatch

import java.util.concurrent.Executors

import java.util.concurrent.Future

fun main() {

Compare().startCompare()

}

class Compare {

private val timeCostMap =mutableMapOf()

fun startCompare() {

testThread()

println("===============================================================================")

Thread.sleep(3000)

testCoroutine()

println("===============================================================================")

var threadTotal =0L

? ? ? ? var coroutineTotal =0L

? ? ? ? timeCostMap.forEach{ t, u->

? ? ? ? ? ? println("$t cost: $u")

if (t.startsWith("Thread")) {

threadTotal += u

}else {

coroutineTotal += u

}

}

? ? ? ? println("Execute $CYCLE_TIME tasks, thread cost: ${threadTotal *1.0 /1000} seconds, coroutine cost: ${coroutineTotal *1.0 /1000} seconds")

}

private fun testThread() {

// init

? ? ? ? val startTime = System.currentTimeMillis()

val countDownLatch = CountDownLatch(CYCLE_TIME)

val maximumOfThread = Runtime.getRuntime().availableProcessors() +1

? ? ? ? val threadPools = Executors.newFixedThreadPool(maximumOfThread){ r-> Thread(r)}

? ? ? ? val resultList =mutableListOf>()

val tasks = getTasks(countDownLatch)

val size = tasks.size

? ? ? ? val initializedTime = System.currentTimeMillis()

println("[Thread]---->? initialized cost: ${initializedTime - startTime}毫秒")

// execute

? ? ? ? for (indexin 0 until size) {

resultList.add(threadPools.submit(tasks[index]))

}

val tasksSubmittedTime = System.currentTimeMillis()

println("[Thread]---->? submit tasks cost: ${tasksSubmittedTime - initializedTime}毫秒")

// check if all task finished

? ? ? ? countDownLatch.await()

val tasksFinishedTime = System.currentTimeMillis()

println("[Thread]---->? execute tasks cost: ${tasksFinishedTime - tasksSubmittedTime}毫秒")

// count time cost

? ? ? ? for (indexin 0 until resultList.size) {

val future = resultList[index]

timeCostMap["Thread: task $index"] = future.get()

}

// all done

? ? }

private fun testCoroutine() {

// init

? ? ? ? val startTime = System.currentTimeMillis()

val countDownLatch = CountDownLatch(CYCLE_TIME)

val tasks = getTasks(countDownLatch)

val size = tasks.size

? ? ? ? val initializedTime = System.currentTimeMillis()

println("[Coroutine]---->? initialized cost: ${initializedTime - startTime}毫秒")

// execute

? ? ? ? for (indexin 0 until size) {

GlobalScope.launch {

? ? ? ? ? ? ? ? val costTime = tasks[index].call()

timeCostMap["Coroutine: task $index"] = costTime

}

? ? ? ? }

val tasksSubmittedTime = System.currentTimeMillis()

println("[Coroutine]---->? submit tasks cost: ${tasksSubmittedTime - initializedTime}毫秒")

// check if all task finished

? ? ? ? countDownLatch.await()

val tasksFinishedTime = System.currentTimeMillis()

println("[Coroutine]---->? execute tasks cost: ${tasksFinishedTime - tasksSubmittedTime}毫秒")

// all done

? ? }

private fun getTasks(countDownLatch: CountDownLatch): MutableList {

val tasks =mutableListOf()

for (indexin 0 until CYCLE_TIME) {

tasks.add(Task(countDownLatch))

}

return tasks

}

inner class Task(private val countDownLatch: CountDownLatch) : Callable {

private fun taskLogics(): Long {

val startTIme = System.currentTimeMillis()

for (countin 0 until 10) {

for (startin 0 until _G) {

val i = System.currentTimeMillis() /3

? ? ? ? ? ? ? ? }

}

countDownLatch.countDown()

return System.currentTimeMillis() - startTIme

}

override fun call(): Long {

return taskLogics()

}

}

companion object {

const val _BYTE =1

? ? ? ? const val _K =1024 *_BYTE

? ? ? ? const val _M =1024 *_K

? ? ? ? const val _G =1024 *_M

? ? ? ? const val CYCLE_TIME =20

? ? }

}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市郎汪,隨后出現(xiàn)的幾起案子赤赊,更是在濱河造成了極大的恐慌,老刑警劉巖煞赢,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件抛计,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡照筑,警方通過(guò)查閱死者的電腦和手機(jī)吹截,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)凝危,“玉大人波俄,你說(shuō)我怎么就攤上這事《昴” “怎么了懦铺?”我有些...
    開封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)支鸡。 經(jīng)常有香客問(wèn)我冬念,道長(zhǎng),這世上最難降的妖魔是什么牧挣? 我笑而不...
    開封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任急前,我火速辦了婚禮,結(jié)果婚禮上瀑构,老公的妹妹穿的比我還像新娘裆针。我一直安慰自己,他們只是感情好检碗,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著码邻,像睡著了一般折剃。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上像屋,一...
    開封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天怕犁,我揣著相機(jī)與錄音,去河邊找鬼。 笑死奏甫,一個(gè)胖子當(dāng)著我的面吹牛戈轿,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播阵子,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼思杯,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了挠进?” 一聲冷哼從身側(cè)響起色乾,我...
    開封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎领突,沒想到半個(gè)月后暖璧,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡君旦,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年澎办,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片金砍。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡局蚀,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出捞魁,到底是詐尸還是另有隱情至会,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布谱俭,位于F島的核電站奉件,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏昆著。R本人自食惡果不足惜县貌,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望凑懂。 院中可真熱鬧煤痕,春花似錦、人聲如沸接谨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)脓豪。三九已至巷帝,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間扫夜,已是汗流浹背楞泼。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工驰徊, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人堕阔。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓棍厂,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親超陆。 傳聞我的和親對(duì)象是個(gè)殘疾皇子牺弹,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容