加入收藏 | 设为首页 | 会员中心 | 我要投稿 河北网 (https://www.hebeiwang.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 移动互联 > 正文

你知道为什么Python这么慢?

发布时间:2018-10-29 21:30:53 所属栏目:移动互联 来源:Anthony Shaw
导读:Python 此刻越来越火,已经敏捷扩张到包罗 DevOps、数据科学、Web 开拓、信息安详等各个规模傍边。 然而,对比起 Python 扩张的速率,Python 代码的运行速率就显得有点逊色了。 在代码运行速率方面,Java、C、C++、C# 和 Python 要怎样举办较量呢?并没有
副问题[/!--empirenews.page--]

 为什么Python这么慢?

Python 此刻越来越火,已经敏捷扩张到包罗 DevOps、数据科学、Web 开拓、信息安详等各个规模傍边。

然而,对比起 Python 扩张的速率,Python 代码的运行速率就显得有点逊色了。

在代码运行速率方面,Java、C、C++、C# 和 Python 要怎样举办较量呢?并没有一个放之四海而皆准的尺度,由于详细功效很洪流平上取决于运行的措施范例,而说话基准测试Computer Language Benchmarks Games可以作为权衡的一个方面。

按照我这些年来举办说话基准测试的履素来看,Python 比许多说话运行起来都要慢。无论是行使 JIT 编译器的 C#、Java,照旧行使 AOT 编译器的 C、C++,又可能是 JavaScript 这些表明型说话,Python 都比它们运行得慢。

留意:对付文中的 “Python” ,一样平常指 CPython 这个官方的实现。虽然我也会在本文中提到其余说话的 Python 实现。

我要答复的是这个题目:对付一个相同的措施,Python 要比其余说话慢 2 到 10 倍不等,这个中的缘故起因是什么?又有没有改进的要领呢?

主流的说法有这些:

  • “是全局表明器锁Global Interpreter Lock(GIL)的缘故起因”
  • “是由于 Python 是表明型说话而不是编译型说话”
  • “是由于 Python 是一种动态范例的说话”

哪一个才是是影响 Python 运行服从的首要缘故起因呢?

是全局表明器锁的缘故起因吗?

此刻许多计较机都配备了具有多个核的 CPU ,偶然乃至还会有多个处理赏罚器。为了更充实操作它们的处理赏罚手段,操纵体系界说了一个称为线程的初级布局。某一个历程(譬喻 Chrome 赏识器)可以成立多个线程,在体系内执行差异的操纵。在这种环境下,CPU 麋集型历程就可以跨焦点分管负载了,这样的做法可以大大进步应用措施的运行服从。

譬喻在我写这篇文章时,我的 Chrome 赏识器打开了 44 个线程。必要说起的是,基于 POSIX 的操纵体系(譬喻 Mac OS、Linux)和 Windows 操纵体系的线程布局、API 都是差异的,因此操纵体系还认真对各个线程的调治。

假如你还没有写过多线程执行的代码,你就必要相识一下线程锁的观念了。多线程历程比单线程历程更为伟大,是由于必要行使线程锁来确保统一个内存地点中的数据不会被多个线程同时会见或变动。

CPython 表明器在建设变量时,起首会分派内存,然后对该变量的引用举办计数,这称为引用计数reference counting。假如变量的引用数变为 0,这个变量就会从内存中开释掉。这就是在 for 轮回代码块内建设姑且变量不会增进内存耗损的缘故起因。

而当多个线程内共享一个变量时,CPython 锁定引用计数的要害就在于行使了 GIL,它会审慎地节制线程的执行环境,无论同时存在几多个线程,表明器每次只应承一个线程举办操纵。

这会对 Python 措施的机能有什么影响?

假如你的措施只有单线程、单历程,代码的速率和机能不会受到全局表明器锁的影响。

但假如你通过在单历程中行使多线程实现并发,而且是 IO 麋集型(譬喻收集 IO 或磁盘 IO)的线程,GIL 竞争的结果就很明明晰。

由 David Beazley 提供的 GIL 竞争环境图http://dabeaz.blogspot.com/2010/01/python-gil-visualized.html

由 David Beazley 提供的 GIL 竞争环境图http://dabeaz.blogspot.com/2010/01/python-gil-visualized.html

对付一个 web 应用(譬喻 Django),同时还行使了 WSGI,那么对这个 web 应用的每一个哀求都运行一个单独的 Python 表明器,并且每个哀求只有一个锁。同时由于 Python 表明器的启动较量慢,某些 WSGI 实现还具有“保卫历程模式”,可以使 Python 历程一向停当。

其余的 Python 表明器示意怎样?

PyPy 也是一种带有 GIL 的表明器,但凡是比 CPython 要快 3 倍以上。

Jython 则是一种没有 GIL 的表明器,这是由于 Jython 中的 Python 线程行使 Java 线程来实现,而且由 JVM 内存打点体系来举办打点。

JavaScript 在这方面又是奈何做的呢?

全部的 Javascript 引擎行使的都是 mark-and-sweep 垃圾网络算法,而 GIL 行使的则是 CPython 的内存打点算法。

JavaScript 没有 GIL,并且它是单线程的,也不必要用到 GIL, JavaScript 的变乱轮回和 Promise/Callback 模式实现了以异步编程的方法取代并发。在 Python 傍边也有一个相同的 asyncio 变乱轮回。

是由于 Python 是表明型说话吗?

我常常会听到这个说法,可是这过于粗陋地简化了 Python 所现实做的事变了。着实当终端上执行 python myscript.py 之后,CPython 会对代码举办一系列的读取、语法说明、理会、编译、表明和执行的操纵。

假如你对这一系列进程感乐趣,也可以阅读一下我之前的文章:在 6 分钟内修改 Python 说话 。

.pyc 文件的建设是这个进程的重点。在代码编译阶段,Python 3 会将字节码序列写入 __pycache__/ 下的文件中,而 Python 2 则会将字节码序列写入当前目次的 .pyc 文件中。对付你编写的剧本、导入的全部代码以及第三方模块都是云云。

因此,绝大大都环境下(除非你的代码是一次性的……),Python 城市表明字节码并当地执行。与 Java、C#.NET 对比:

Java 代码会被编译为“中间说话”,由 Java 假造机读取字节码,并将其即时编译为呆板码。.NET CIL 也是云云,.NET CLR(Common-Language-Runtime)将字节码即时编译为呆板码。

既然 Python 像 Java 和 C# 那样都行使假造机或某种字节码,为什么 Python 在基准测试中如故比 Java 和 C# 慢得多呢?主要缘故起因是,.NET 和 Java 都是 JIT 编译的。

(编辑:河北网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读