从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… 做者信息:朱德龙,人和将来高级前端工程师。

相关文章
相关标签/搜索