<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Java、Go 和 Python 的多線程性能哪個(gè)更好呢?

          共 4595字,需瀏覽 10分鐘

           ·

          2022-06-26 14:16

          今天分享多線程下這三門語言的表現(xiàn)。

          簡(jiǎn)介

          在計(jì)算機(jī)中,線程是可以由處理器獨(dú)立執(zhí)行的小指令序列。多線程在一個(gè)進(jìn)程中是可能的,其中它們共享資源,例如指令和上下文。

          發(fā)現(xiàn)在運(yùn)行多線程進(jìn)程時(shí)效率最高的編程語言非常重要,因?yàn)樗梢詭椭浖_發(fā)人員同時(shí)選擇最有利的語言來實(shí)現(xiàn)他們的系統(tǒng)。

          本文的目的是分析和比較 Java、Go 和 Python 使用它們的并行工具解決幾種算法的性能,例如:Java 和 Python 的線程,以及 Go 的 goroutine。為了評(píng)估性能,我們編寫了經(jīng)典矩陣乘法算法、快速排序算法和康威生存游戲(Conway’s game of life)的并行實(shí)現(xiàn)。

          背景

          Java :它是一種面向?qū)ο蟮木幊陶Z言,通過Thread類、Runnable接口和java.util.concurrent包中包含的其他功能內(nèi)置支持并發(fā)。

          Go:它是谷歌在 2012 年發(fā)布的一種編程語言。它是一種類似于 C 的語言,并且具有垃圾收集器和內(nèi)置的并發(fā)支持。對(duì)于并發(fā)性和并行性,Go 使用稱為 goroutines 的線程實(shí)現(xiàn)。它使用內(nèi)置的調(diào)度程序在后臺(tái)處理線程,并試圖向用戶隱藏通常線程管理的大部分復(fù)雜性,以支持簡(jiǎn)單地指定要運(yùn)行的函數(shù)并使用 go 命令為它們開頭。Go 在幕后使用操作系統(tǒng) (OS) 線程。

          Python:標(biāo)準(zhǔn)庫 threading,這個(gè)模塊封裝了線程,提供了一個(gè)干凈的接口來處理它們。在這種方法中,操作系統(tǒng)實(shí)際上知道每個(gè)線程,并且可以隨時(shí)中斷它以開始運(yùn)行不同的線程。使用 Python 的其他標(biāo)準(zhǔn)庫(稱為 multiprocessing)可以在 Python 中實(shí)現(xiàn)并行性,而 multiprocessing 會(huì)創(chuàng)建新的進(jìn)程。threading 模塊使用線程,multiprocessing 模塊使用進(jìn)程。不同之處之一是線程在相同的內(nèi)存空間中運(yùn)行,而進(jìn)程具有單獨(dú)的內(nèi)存。

          矩陣乘法:它是線性代數(shù)中一個(gè)重要而簡(jiǎn)單的數(shù)學(xué)運(yùn)算,經(jīng)典的矩陣乘法算法(CMMA)可以很容易地用任何編程語言實(shí)現(xiàn)。CMMA 時(shí)間復(fù)雜度 *O(N^3)*,其中 N 是矩陣的維度。

          快速排序:它是一種分而治之的算法。最初,它將數(shù)組拆分為兩個(gè)子數(shù)組:分別是較低的項(xiàng)和較高的項(xiàng)。然后它遞歸地對(duì)這些子數(shù)組進(jìn)行排序。其算法可以描述為:

          1. 從數(shù)組中選擇一個(gè)樞軸元素。
          2. 對(duì)數(shù)組進(jìn)行分區(qū),使得樞軸左側(cè)的所有元素的值都小于樞軸的值,而樞軸右側(cè)的所有元素的值都大于樞軸的值。
          3. 對(duì)生成的子數(shù)組遞歸執(zhí)行上述步驟,直到得到完全排序的子數(shù)組。

          它的平均排序復(fù)雜度為*O(nlog(n)),但在極少數(shù)情況下會(huì)降級(jí)為O(n^2)*。

          康威的生存游戲:它是由劍橋大學(xué)岡維爾和凱斯學(xué)院的數(shù)學(xué)家約翰霍頓康威在 60 年代開發(fā)的。規(guī)則是:

          1. 規(guī)則 1 生存:如果一個(gè)活細(xì)胞有兩個(gè)或三個(gè)活的鄰居,它就可以生存。
          2. 規(guī)則 2 死亡:如果一個(gè)活細(xì)胞的存活鄰居少于兩個(gè)或多于三個(gè),它就會(huì)死亡。
          3. 規(guī)則 3 出生:如果一個(gè)死細(xì)胞恰好有三個(gè)活著的鄰居,它就會(huì)出生。

          下圖片顯示了康威生存游戲從時(shí)間 T 到時(shí)間 T + 2 的幾個(gè)場(chǎng)景。該算法的一個(gè)簡(jiǎn)單實(shí)現(xiàn)將檢查每一步的每個(gè)單元格,其時(shí)間復(fù)雜度為 O(M × N ),其中 M 表示行數(shù),N 表示網(wǎng)格的列數(shù)。

          It shows several scenarios of Conway’s game of life from time T to time T + 2

          解決方案

          所有基準(zhǔn)測(cè)試都在同一臺(tái)計(jì)算機(jī)和同一環(huán)境中執(zhí)行。表 I 顯示了我們進(jìn)行實(shí)驗(yàn)的硬件規(guī)格,表 II 顯示了每種語言編程編譯器的版本

          硬件和編程語言軟件概覽

          對(duì)于每個(gè)基準(zhǔn),我們計(jì)算其各自的加速和效率。加速定義為最佳順序時(shí)間與p個(gè)處理器的并行時(shí)間之比:S = T1/Tp。那么效率定義為:并行系統(tǒng)中每個(gè)處理器的總體利用率:E = S/p

          矩陣乘法:在本實(shí)驗(yàn)中,我們使用由C = AB計(jì)算的簡(jiǎn)單矩陣乘法。矩陣的大小為 512 × 512。我們正在運(yùn)行一個(gè)順序場(chǎng)景,然后是幾個(gè)線程池大小為:2、4、8、16 和 32 個(gè)線程的多線程場(chǎng)景。相同的矩陣AB用于運(yùn)行 Java、Go 和 Python 中的代碼。這些矩陣將具有從 0 到 1000 的整數(shù)值(包括 0 到 1000)。線程池將接收 n 個(gè)工作,表示矩陣 A 中的行數(shù),然后每個(gè)線程將執(zhí)行該特定行的乘法,并更新C中的相應(yīng)行與得到的結(jié)果。每次線程完成其工作時(shí),它將從線程池接收新的分配,直到所有工作都完成。下圖說明了矩陣C的計(jì)算。

          矩陣乘法

          快速排序:我們從 0 到 10^7(包括 0 和 10^7)對(duì) 10^7 個(gè)整數(shù)值的數(shù)組進(jìn)行排序。我們使用 ForkJoinPool 方法來解決這個(gè)實(shí)驗(yàn)。執(zhí)行順序運(yùn)行,然后多線程測(cè)試以 2 的冪從 2 到 32 個(gè)線程。這 3 個(gè)實(shí)現(xiàn)對(duì)同一個(gè)數(shù)組進(jìn)行排序。在快速排序的并行實(shí)現(xiàn)中,分區(qū)后新子序列的排序可以并行執(zhí)行,因?yàn)闆]有沖突。

          康威生存游戲:康威生存游戲中有幾個(gè)初始已知模式會(huì)產(chǎn)生預(yù)期的結(jié)果,有一個(gè)會(huì)無限增長(zhǎng),下一張圖像的左側(cè)顯示其初始設(shè)置。在這個(gè)基準(zhǔn)測(cè)試中,我們定義了一個(gè) 28 × 28 的 2D 網(wǎng)格,其中 4 個(gè)先前的模式彼此相鄰,并在 20,000 代期間執(zhí)行游戲,該網(wǎng)格看起來像下圖的右側(cè)。

          無限增長(zhǎng)模式

          對(duì)于這個(gè)實(shí)驗(yàn),我們重復(fù)線程池方法,它將處理 2、4、8、16 和 32 個(gè)線程。此外,我們運(yùn)行順序?qū)崿F(xiàn)。我們并行應(yīng)用了決定細(xì)胞在每一代中是否繼續(xù)生存、死亡或重生的規(guī)則。此外,為了獲取單元格的鄰居,我們不會(huì)將網(wǎng)格視為無限網(wǎng)格,如果單元格的鄰居在世界范圍之外,則認(rèn)為它已死。

          結(jié)果

          矩陣乘法:表 III 顯示了運(yùn)行矩陣乘法基準(zhǔn)后獲得的結(jié)果。Java 是順序執(zhí)行中最好的,它在 316 毫秒內(nèi)運(yùn)行了 512 × 512 矩陣乘法,而 Go 消耗了 453 毫秒,這代表順序運(yùn)行的時(shí)間增加了 43.35%。性能最差的是 Python,它使用了 93,870 毫秒(93.87 秒),相差約 29,600%。

          此外,在表 III 中可以看出,當(dāng)使用 2 個(gè)線程執(zhí)行基準(zhǔn)測(cè)試時(shí),Java 性能更好,但是當(dāng)實(shí)驗(yàn)在 4、8 和 16 個(gè)線程中運(yùn)行時(shí),Go 優(yōu)于 Java 和 Python。我們可以在 32 個(gè)線程的閾值處檢測(cè)到性能下降,這可能是由于創(chuàng)建過多線程的開銷超過了 CPU 中的物理內(nèi)核;即使在這種惡化的情況下,Go 的性能也優(yōu)于其他兩種語言。

          矩陣乘法時(shí)間消耗(以毫秒為單位)。越低越好。

          下圖的左側(cè)反映了對(duì)于 Go,從 2 到 4 個(gè)線程的性能差異是顯著的(大約 92% 的改進(jìn)),而從 8 到 16 個(gè)線程它是微不足道的,因?yàn)閳D中的曲線幾乎保持不變,這說明我們認(rèn)為 8 個(gè)線程對(duì)于這個(gè)特定場(chǎng)景來說是一個(gè)很好的數(shù)字。另一方面,Java 的性能從 2 個(gè)線程穩(wěn)步增加到 16 個(gè)線程;從這個(gè)圖中,我們可以選擇 16 個(gè)線程作為大量線程,以便在 Java 中獲得不錯(cuò)的性能。從下圖右側(cè)可以確定,資源利用效率最差的是Python,最好的是Go。

          矩陣乘法的加速和效率。

          快速排序:在表 IV 中,我們可以看到 Go 在測(cè)試的順序運(yùn)行中獲得最佳性能,而 Python 最差。Python 實(shí)現(xiàn)的一般行為非常糟糕,在 16 和 32 線程的情況下,應(yīng)用程序無法完成執(zhí)行(DNF 代表沒有完成)卡住并阻塞計(jì)算機(jī)。Go 提供了有趣的結(jié)果,因?yàn)槎嗑€程運(yùn)行從糟糕到最差的性能。對(duì)于這個(gè)度量,Java 獲得了最好的多線程結(jié)果,但是在 16 和 32 線程的運(yùn)行中,我們可以發(fā)現(xiàn)性能下降,其中 16 線程的性能最差。

          快速排序時(shí)間消耗(以毫秒為單位)。越低越好。

          下圖左側(cè)的加速表明,當(dāng)使用 Java 實(shí)現(xiàn)時(shí),使用超過 8 個(gè)線程運(yùn)行快速排序算法是沒有意義的。此外,我們可以看到 32 線程的運(yùn)行比 16 線程的運(yùn)行好一點(diǎn),但比 8 線程的運(yùn)行差。該圖反映了 Go 多線程實(shí)現(xiàn)不如順序?qū)崿F(xiàn)。即使 Python 的性能很差,使用 2、4 和 8 個(gè)線程的運(yùn)行也比順序運(yùn)行要好。

          下圖右側(cè)反映的效率證實(shí)了我們?cè)诒?IV 中看到的最好的,但不是最差的,因?yàn)檫@個(gè)圖可以讓我們認(rèn)為 Python 比 Go 更好,但是時(shí)間的消耗告訴我們一段不同的歷史:Go 的表現(xiàn)優(yōu)于 Python。

          快速排序的加速和效率。

          康威的生存游戲:Python 再次獲得了所有 3 種實(shí)現(xiàn)中最差的結(jié)果,但是正如我們?cè)诒?V 中看到的,它是唯一一個(gè)從順序?qū)崿F(xiàn)到多線程實(shí)現(xiàn)有一些改進(jìn)的版本;盡管如此,隨著線程數(shù)量的增加,時(shí)間的消耗也會(huì)增加。在 Java 和 Go 的情況下,它們的最佳性能來自順序?qū)崿F(xiàn)。在 Java 場(chǎng)景中,從順序版本到具有 32 個(gè)線程的版本的時(shí)間差異為 11,455%,這代表了當(dāng)時(shí)的巨大差距。在 Java 實(shí)現(xiàn)中,每一代之后都會(huì)釋放線程池并創(chuàng)建一個(gè)新的線程池,這會(huì)產(chǎn)生相當(dāng)大的開銷。Go 行為不穩(wěn)定,時(shí)間利用率從順序到 2 線程版本增加,然后在 4、8 和 16 個(gè)線程的版本中,它會(huì)稍微減少一點(diǎn),最后在 32 個(gè)線程時(shí),它會(huì)再次增加。

          康威的生存時(shí)間消耗游戲(以毫秒為單位)。越低越好。

          下圖的加速圖證實(shí)了康威生存游戲的多線程實(shí)現(xiàn)的一般性能很差。圍繞加速曲線的期望是它應(yīng)該遵循增加的行為,而這并沒有發(fā)生。報(bào)告的效率表明資源沒有得到適當(dāng)?shù)睦谩ava 的效率非常接近于零,Go 和 Java 之間只有一點(diǎn)點(diǎn)差異。

          康威生存游戲的加速和效率。

          結(jié)論

          創(chuàng)建線程的開銷直接影響應(yīng)用程序的性能。在表 III 中可以看出,在達(dá)到某個(gè)閾值后繼續(xù)創(chuàng)建線程是沒有意義的,因?yàn)樾阅軙?huì)下降。

          如表 V 所示,使用多線程解決問題并不能保證我們會(huì)獲得更好的性能,有時(shí)順序?qū)崿F(xiàn)是最好的選擇。

          處理并發(fā)性和并行性的 Python 標(biāo)準(zhǔn)庫不如 Java 和 Go 等其他編程語言中實(shí)現(xiàn)的標(biāo)準(zhǔn)庫。

          很難說 Java 和 Go 之間哪個(gè)更好,因?yàn)?Java 在矩陣乘法基準(zhǔn)測(cè)試中優(yōu)于 Go,但 Go 在快速排序?qū)嶒?yàn)中超過了 Java。

          未來的工作

          這項(xiàng)工作僅限于每個(gè)算法的基本實(shí)現(xiàn),下一步將是復(fù)制本研究引入的場(chǎng)景,但使用每個(gè)基準(zhǔn)測(cè)試的最知名實(shí)現(xiàn)。

          在 Python 中實(shí)現(xiàn)并行代碼有多種選擇,例如:MPI for Python、CharmPy、Numba 等。一個(gè)好的實(shí)驗(yàn)是使用這個(gè)庫用更有效的實(shí)現(xiàn)來替換書面代碼。

          擴(kuò)展這項(xiàng)研究的一種方法是考慮其他技術(shù)方面,例如編譯時(shí)間、文件大小和編寫的代碼行數(shù)。

          作者:Jose Pablo,原文鏈接:https://levelup.gitconnected.com/java-go-and-python-a-multi-thread-performance-comparison-28e942cb73e6。



          往期推薦


          我是 polarisxu,北大碩士畢業(yè),曾在 360 等知名互聯(lián)網(wǎng)公司工作,10多年技術(shù)研發(fā)與架構(gòu)經(jīng)驗(yàn)!2012 年接觸 Go 語言并創(chuàng)建了 Go 語言中文網(wǎng)!著有《Go語言編程之旅》、開源圖書《Go語言標(biāo)準(zhǔn)庫》等。


          堅(jiān)持輸出技術(shù)(包括 Go、Rust 等技術(shù))、職場(chǎng)心得和創(chuàng)業(yè)感悟!歡迎關(guān)注「polarisxu」一起成長(zhǎng)!也歡迎加我微信好友交流:gopherstudio


          瀏覽 71
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  三级片网站欧美 | 乱伦电影影音先锋 | 国产蜜臀AV一区二区 | 青娱乐免费视频 | 99久久婷婷国产综合精品青牛牛 |