It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened,
visit the help center。
9年前关闭。
我的理解
C++被编译成机器代码并执行。
Python被编译成字节码
然后执行此字节码
这个执行步骤需要什么,对于Cpython和PyPy有何不同?
绩效差异从何而来?
就性能而言,Python是动态键入的事实在哪里呢?
谢谢!
C,C++和其他静态编译的语言被编译成本机代码,这意味着计算机的CPU可以直接执行它们。它所编译的代码是难以理解的二进制数据,但是您可以想象一下一个C代码片段,如下所示:
int x = 10;
int y = x * 2;
将被编译为一系列二进制指令,这些指令的含义如下:
store 10 into memory address 200
multiply the contents of memory address 200 by 2, treating them as integers
store the result of the last instruction into memory address 300
编译器已将内存地址分配给代码中出现的变量
x
和
y
的位置。请注意,实际的机器代码比这复杂得多,并且显然被编码为简短的二进制代码字,而不是英语短语。但这是最基本的想法。需要特别注意的一点是,编译器知道使用整数乘法,因为它知道
x
和
y
是整数。 CPU本身对存储器地址200的内容的含义一无所知,它只知道位,并且可以被告知以各种方式对其进行混洗,其中之一是整数乘法。
现在,Python已编译为字节码。当我们谈论这些问题时,这实际上并不意味着非常有趣。 Python字节码与机器代码不同,
并不编码可以由机器直接执行的低级操作。实际上,它基本上只是对您在Python源代码中编写的相同的Python级操作进行编码,而CPU使用Python字节代码根本无法执行任何操作。 Python解释器是一个程序,用于执行以Python字节码编码的指令。字节码编译所做的所有工作就是允许解释器以一种更易于操作的代码形式进行操作。它不必进行直接了解Python源代码所需的所有字符串处理。
因此,这里出现了动态类型输入和性能差异的地方。看到
x * 2
的C++编译器知道可以将其编译为CPU的单个整数乘法指令
,因为它知道之前涉及的所有类型。
可以看到
x * 2
的Python解释器必须经过许多步骤才能确定
x
是支持乘法的内置类型中的任何一种,还是实现自定义乘法的类,还是不是实现乘法的类?但继承自其他行为或是否应创建异常。如果
x
是整数,则需要执行一些步骤以从表示Python整数的数据结构中获取
x
的机器级值,然后执行1个单机器级指令以实际让CPU执行整数乘法,然后再执行更多指令将结果包装回Python整数数据结构。
所有这些代码都是许多编译的机器代码指令(通常;对于在CPython之上运行的PyPy,它们是Python字节代码指令!); Python解释器本身的编译代码。您可能会认为Python的字节码编译器可以提前找出哪个路径,并将Python源代码转换为这些机器指令,但这不能,因为Python是动态类型的。
x
在第一次执行该行代码时可以是整数,在下次执行时可以是一个字符串,在之后的时间可以是一个列表,甚至有一天是一个类实例。因此所有这些逻辑必须每次都完成,因为Python无法提前知道它会需要什么。因此,即使您编写了将Python源代码编译成本机机器代码的程序,大多数情况下,它也必须发出基本上与Python解释器相同功能的机器代码。
作为一个非常简单的概述,它涵盖了您的大多数问题。您还会询问PyPy,而没有真正提供您感兴趣的任何细节。我想这是“为什么PyPy有时比CPython快?” PyPy基本上有一个JIT编译器,它有点像C++编译器,只是它在程序执行期间编译代码。 (有时)可以解决Python无法知道
x
是整数,浮点数,列表还是其他东西的问题。只要执行一点代码,
x
就是一回事。在大多数Python代码中,
x
只是一件事,或者偶尔是其中的几件事。因此,通过在运行时编译代码(在等待看到真正执行的代码之后),PyPy的JIT
可以(有时)将
x * 2
转换为单个整数乘法机器代码指令。如果我们使用
x
作为整数百万次执行该行代码,这将大大提高性能。但是下一次
x
仍然有可能是一个字符串,因此JIT必须包含一些后备逻辑,以便它仍然可以处理Python允许的所有可能性。但是它可以通过等待查看实际经常使用的多种可能性中的哪一种,然后对其进行优化来提高速度。 JIT甚至可以做一些C++编译器无法做到的优化,因为它可以等待观察运行时发生了什么,而C++必须发出可以在运行时发生任何事情的代码(但它可以根据类型进行假设) ,它将永远不会改变)。
我是一名优秀的程序员,十分优秀!