這篇文章主要講解了“怎么理解Scala循環(huán)性能問(wèn)題”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“怎么理解Scala循環(huán)性能問(wèn)題”吧!
成都創(chuàng)新互聯(lián)是一家集網(wǎng)站建設(shè),沂南企業(yè)網(wǎng)站建設(shè),沂南品牌網(wǎng)站建設(shè),網(wǎng)站定制,沂南網(wǎng)站建設(shè)報(bào)價(jià),網(wǎng)絡(luò)營(yíng)銷(xiāo),網(wǎng)絡(luò)優(yōu)化,沂南網(wǎng)站推廣為一體的創(chuàng)新建站企業(yè),幫助傳統(tǒng)企業(yè)提升企業(yè)形象加強(qiáng)企業(yè)競(jìng)爭(zhēng)力??沙浞譂M(mǎn)足這一群體相比中小企業(yè)更為豐富、高端、多元的互聯(lián)網(wǎng)需求。同時(shí)我們時(shí)刻保持專(zhuān)業(yè)、時(shí)尚、前沿,時(shí)刻以成就客戶(hù)成長(zhǎng)自我,堅(jiān)持不斷學(xué)習(xí)、思考、沉淀、凈化自己,讓我們?yōu)楦嗟钠髽I(yè)打造出實(shí)用型網(wǎng)站。
最近我在學(xué)習(xí)我們產(chǎn)品的代碼,看到了類(lèi)似以下的一段代碼:
x.set(1) x.set(2) x.set(3) x.set(4) x.set(5)
我當(dāng)時(shí)很是疑惑,為什么不用循環(huán)呢?于是就報(bào)了一個(gè)Issue,心想這樣寫(xiě)可能有它的道理,但是需要澄清一下。
另一個(gè)問(wèn)題,就是我發(fā)現(xiàn)代碼里對(duì)循環(huán)的使用,各有不同的方式,有人寫(xiě)array.foreach(f=>_),有人用使用index的for loop,個(gè)人覺(jué)得使用foreach的代碼比較簡(jiǎn)潔,于是我也報(bào)了Issue,看看是不是應(yīng)該使用簡(jiǎn)潔的方式來(lái)寫(xiě)循環(huán)。舉例:
for loop
var index = 0 var arr = Array[String] var length = arr.length for ( index <- 0 to length ) { do() }
for each
var index = 0 var arr = Array[String] var length = arr.length for ( index <- 0 to length ) { do() }
明顯foreach的版本要省不少代碼。
后來(lái)和我們的工程師溝通了一下,原來(lái)我們是為了性能優(yōu)化了代碼,因?yàn)閒or loop比f(wàn)oreach的性能好,所以我們采用稍微繁瑣的for loop。至于某些代碼中的foreach是因?yàn)檫z留的還沒(méi)有來(lái)得及改動(dòng)。
Scala的循環(huán)就行性能如何呢?我還是測(cè)試一下再說(shuō)吧。
先看看不同的循環(huán)用法,我這里測(cè)試了四種,分別是 while loop,for loop,使用range的foreach, 和使用函數(shù)的foreach。
測(cè)試代碼如下:
package profiling object Loop { def whileLoop(arr:Array[Int]): Unit = { var idx = 0 var n = arr.length val tStart = System.currentTimeMillis() while (idx < n) { arr(idx) = 1 idx += 1 } val tEnd = System.currentTimeMillis() println("while loop took " + (tEnd - tStart) + "ms") } def forLoop(arr:Array[Int]): Unit = { var idx = 0 var n = arr.length val tStart = System.currentTimeMillis() for(idx <- 0 until n) { arr(idx) = 1 } val tEnd = System.currentTimeMillis() println("for loop took " + (tEnd - tStart) + "ms") } def foreachLoop(arr:Array[Int]): Unit = { var n = arr.length val tStart = System.currentTimeMillis() (0 until n).foreach{idx => arr(idx) = 1} val tEnd = System.currentTimeMillis() println("foreach range took " + (tEnd - tStart) + "ms") } def foreachFuncLoop(arr:Array[Int]): Unit = { val tStart = System.currentTimeMillis() arr.foreach{ idx => arr(idx) = 1} val tEnd = System.currentTimeMillis() println("foreach function took " + (tEnd - tStart) + "ms") } def profileRun(n: Int) { val arr = new Array[Int](n) whileLoop(arr) foreachLoop(arr) forLoop(arr) foreachFuncLoop(arr) } def main(args:Array[String]) { profileRun(args(0).toInt) } }
我的環(huán)境是scala 2.13.1 , 調(diào)用500000000次的結(jié)果是:
Bash 代碼
while loop took 344ms foreach range took 484ms for loop took 422ms foreach function took 719ms
可以看出,while loop是最快的,一般形式的foreach最慢,差不多是while loop的一倍。但是如果使用range的話(huà),foreach循環(huán)也不算太慢。
那么為什么foreach會(huì)慢呢? 主要是foreach的函數(shù)調(diào)用帶來(lái)了額外的開(kāi)銷(xiāo)。我們上面看到的數(shù)據(jù)其實(shí)是編譯器已經(jīng)優(yōu)化后的數(shù)字,如果我們把java的hotspot編譯選項(xiàng)關(guān)閉,(-Xint)再看看性能。
while loop took 8548ms foreach range took 39392ms for loop took 40799ms foreach function took 103489ms
如果關(guān)閉JIT,foreach的性能要遠(yuǎn)遠(yuǎn)差于其他幾個(gè)選項(xiàng)。
對(duì)于循環(huán)的性能,我們可以得出這樣的結(jié)論:
在正常打開(kāi)JIT的情況下,foreach的性能大概比其他幾個(gè)選項(xiàng)慢一倍,其他幾個(gè)選項(xiàng)性能接近
在關(guān)閉JIT優(yōu)化的情況下。foreach的性能要遠(yuǎn)低于其他選項(xiàng) (生產(chǎn)環(huán)境一般不考慮)
那么對(duì)于開(kāi)頭講的不用循環(huán),直接重復(fù)代碼呢?我們也測(cè)試了一下:
package profiling object Loop2Repeat { def whileLoop(): Unit = { var idx = 0 var n = 5 var x = 0 while (idx < n) { x = idx idx += 1 } } def repeatLoop(): Unit = { var x = 0 x = 1 x = 2 x = 3 x = 4 x = 5 } def test( f:()=>Unit, num: Int, name: String): Unit = { val tStart = System.currentTimeMillis() ( 0 until num).foreach{ _ => f} val tEnd = System.currentTimeMillis() println(name + " took " + (tEnd - tStart) + "ms") } def main(args:Array[String]) { test(whileLoop, 50000000, "whileLoop") test(repeatLoop, 50000000, "repeatLoop") } }
經(jīng)過(guò)50000000次循環(huán),數(shù)據(jù)如下:
whileLoop took 281ms repeatLoop took 47ms
確實(shí),因?yàn)檠h(huán)控制的邏輯帶來(lái)的額外開(kāi)銷(xiāo),比簡(jiǎn)單的重復(fù)代碼性能下降了不少。
感謝各位的閱讀,以上就是“怎么理解Scala循環(huán)性能問(wèn)題”的內(nèi)容了,經(jīng)過(guò)本文的學(xué)習(xí)后,相信大家對(duì)怎么理解Scala循環(huán)性能問(wèn)題這一問(wèn)題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!
網(wǎng)站欄目:怎么理解Scala循環(huán)性能問(wèn)題
文章位置:http://muchs.cn/article22/ijdejc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供微信公眾號(hào)、網(wǎng)站維護(hù)、品牌網(wǎng)站建設(shè)、關(guān)鍵詞優(yōu)化、服務(wù)器托管、靜態(tài)網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話(huà):028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)