從JavaScript到Python之併發(上)

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

測試環境:前端

操做系統: win10 x64
CPU: Intel i5-8400 6核6線程
複製代碼

實現併發操做通常來講有3種方式:進程線程協程git

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

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

進程

進程是系統進行資源分配和調度的基本單位。瀏覽器

JavaScript

瀏覽器端執行的JavaScript沒有多進程的概念,因此只考慮Node.js上的多進程。bash

讓不一樣的進程運行在不一樣的內核上才能最好地發揮並行的優點,爲了達到這個目的,咱們選取原生模塊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… 做者信息:朱德龍,人和將來高級前端工程師。

相關文章
相關標籤/搜索