1. 程式人生 > 程式設計 >從JavaScript到Python之併發(上)

從JavaScript到Python之併發(上)

本文通過分析對比探究JavaScript與Python的併發能力,分上下兩篇,上篇探究CPU併發,下篇探究網路IO併發。

測試環境:

作業系統: win10 x64
CPU: Intel i5-8400 6核6執行緒
複製程式碼

實現併發操作一般來說有3種方式:程式執行緒協程

用一個簡單的耗時功能來進行測試:遞迴實現斐波那契數列第n項的計算。

對於CPU密集型的計算任務,要通過併發提升程式執行效率,縮短執行時間,就一定要利用CPU的多核。 下面我們就來看看 JavaScript 和 Python 如何使用這3種方式進行併發以及對CPU核數的利用情況。

程式

程式是系統進行資源分配和排程的基本單位。

JavaScript

瀏覽器端執行的JavaScript沒有多程式的概念,所以只考慮Node.js上的多程式。

讓不同的程式執行在不同的核心上才能最好地發揮並行的優勢,為了達到這個目的,我們選取原生模組cluster

程式碼如下:

為了使結果更準確,開啟資源監視器進行檢視,CPU各個都已跑滿。

執行結果:

消耗時間(s): 8.107
消耗時間(s): 8.118
消耗時間(s): 8.16
消耗時間(s): 8.175
消耗時間(s): 8.209
消耗時間(s): 8.253
複製程式碼

所以總耗時在8.253秒。

為了進一步證實,執行單程式程式碼:

單程式執行結果: 消耗時間(s): 7.361

時間比多程式略少一些,考慮到程式的建立與銷燬所耗的時間,在誤差範圍之內。

Python

Python操作程式的模組為multiprocessing,同樣我們啟動6個程式看看能不能把所有核跑滿。

程式碼如下:

CPU監控也顯示6個核都執行了計算任務:

執行結果

消耗時間(s): 8.683971881866455
消耗時間(s): 8.699971675872803
消耗時間(s): 8.71097183227539
消耗時間(s): 8.84197187423706
消耗時間(s): 8.863972425460815
消耗時間(s): 8.900972843170166
複製程式碼

總執行時間約為8.9秒。

執行時間看上去只比JavaScript慢了那麼一丟丟,但是需要注意的是JavaScript程式碼計算的是數列第45位,Python只計算第38位!

同樣執行一下單程式進行計算,與多程式進行對比驗證。

消耗時間(s): 8.092010259628296

執行時間也相當接近。

結論

JavaScript(Node.js)Python都提供了操作程式的原生模組,多程式執行計算任務時都能有效利用CPU多核提升效率。

執行緒

一個程式可以有一個或多個執行緒,執行緒相對程式而言更輕量,上下文切換成本更低,通常作為併發操作的首選。

JavaScript

前端工程師很少了解執行緒的概念:瀏覽器端直到HTML5標準提出才支援以web worker方式建立多執行緒,Node.js也是12以後的版本才支援使用worker_threads模組進行多執行緒計算。 總結起來就是早期的JavaScript執行環境沒有執行緒相關模組與API,對開發者遮蔽了執行緒的概念。

web worker

瀏覽器端多執行緒執行執行JavaScript程式碼分為兩部分,待執行的js檔案和引入該js檔案的頁面。

程式碼如下:

在本地啟動和訪問伺服器,得到監控影象也是多核執行:

執行結果:

消耗時間(s): 15.989
消耗時間(s): 16.109
消耗時間(s): 16.204
消耗時間(s): 16.874
消耗時間(s): 16.876
消耗時間(s): 16.971
複製程式碼

總執行時間約為16.9秒。

為了使結果更有說服力,我們在瀏覽器控制檯執行一下相關程式碼

時間略少於多執行緒執行。

相對於Node.js端執行多了1倍,看來瀏覽器端的執行緒效能並不高。

worker_threads

不能利用多核一直讓Node.js飽受詬病,新版本算是對這個問題打了個補丁。

Node.js端程式碼如下:

CPU監控結果:

執行結果:

消耗時間(s): 8.229
消耗時間(s): 8.282
消耗時間(s): 8.299
消耗時間(s): 8.403
消耗時間(s): 8.417
消耗時間(s): 8.44
複製程式碼

總時間8.44秒與單獨執行相當。

結論

瀏覽器和Node.js都支援多執行緒,但明顯瀏覽器執行效能不如Node.js,所以使用web worker的工程師需謹慎。

Python

Python的原生模組threading提供多執行緒操作。具體程式碼如下

監控圖表:

看波形圖應該是利用了各個核,但並沒有滿負荷執行。

執行結果也不盡如人意:

消耗時間(s): 38.476489543914795
消耗時間(s): 41.6956250667572
消耗時間(s): 45.613648414611816
消耗時間(s): 47.564653396606445
消耗時間(s): 47.68662452697754
消耗時間(s): 48.57262468338013
複製程式碼

總時間為48.5s,是單程式執行時間的6倍。

結論

從輸出結果時間來看,Python的執行緒是併發執行了,但並沒有提升執行效率。

協程

協程和執行緒有些類似,區別在於執行緒是由作業系統排程的,協程是由使用者程式碼管理的。 相對執行緒而言上下文切換成本更輕量。

Python

抱歉,JavaScript的原生模組目前還不支援。 Python3倒是積極引入了協程的概念,實際作用看測試結果吧~

程式碼:

CPU監控:

執行結果:

消耗時間(s): 8.070001602172852
消耗時間(s): 16.14399790763855
消耗時間(s): 24.214999198913574
消耗時間(s): 32.300398111343384
消耗時間(s): 40.38105368614197
消耗時間(s): 48.451064109802246
複製程式碼

結論

協程在CPU使用率上和執行緒差不多,並沒有提升。而且從輸出結果來看並不是真正的並行執行。

總結

  • 首先不考慮併發的情況下,JavaScript的執行效率要優於Python
  • 兩者都能利用多程式有效地利用CPU多核提升效率。
  • 執行緒JavaScript更勝一籌,Python在受限於全域性直譯器鎖的情況下,多執行緒可以實現併發但不能提升效率。
  • 協程JavaScript完敗,但Python的協程也不擅長處理CPU密集型操作。

原文連結:tech.gtxlab.com/js2py-async… 作者資訊:朱德龍,人和未來高階前端工程師。