spr*_*ksh 4 python java jvm cpython compilation
Java 和 python(仅讨论 CPython)分别被解释为 Java 和 CPython 字节码。然后,这两个字节码都由它们各自的虚拟机(JVM 和 Cpython VM)解释。(这里我忽略了在 10K 运行后开始的 JIT 编译部分。)
我对此有两个问题:
虽然它在运行时扮演着重要的角色,但我认为静态和动态类型在编译过程中不应该扮演太大的角色,也不应该是造成这种时间差异的唯一原因。另外,我认为在这两个实现中,在字节码生成期间进行了一些优化。
有什么我在这里想念的吗?(我没有太多的 Java 工作经验。)
更新:
我实际上对 python 第一次运行和后来的运行做了时间分析,发现语句 2 是错误的。运行大型python文件时有非常明显的区别。
方法很简单。创建了一个包含重复行的大文件
a = 5
b = 6
c = a*b
print(str(c))
然后将其导入文件large.py并运行time python large.py
首次运行结果:
python large.py  1.49s user 0.33s system 97% cpu 1.868 total
第二次运行结果:
python large.py  0.20s user 0.08s system 90% cpu 0.312 total
删除 __pycache__ 文件夹后:
python large.py  1.57s user 0.34s system 97% cpu 1.959 total
所以基本上在 python 中,编译为字节码是一个昂贵的过程,只是它不像在 java 中那么昂贵。
Java 字节码编译器必须比 Python 字节码编译器做更多的检查。为了说明这一点,请从“hello world”程序中取出这一行:
System.out.println("Hello World!");
要编译这行代码,编译器必须找出其所有部分的含义。这比听起来更复杂:System可能是一个包。或者它可以是一个类,或者在代码所在的同一个包中,或者在一个导入的包中,或者在java.lang. 所以编译器必须按顺序检查所有这些选项。一旦找到System该类,它就必须检查其访问修饰符是否允许这种使用。
之后,编译器必须弄清楚什么out是:它是嵌套类还是类成员,以及它的访问修饰符是什么?编译器发现它是类型的静态成员变量PrintStream。然后它必须对println. 编译器在知道所有这些之前不能为这行代码发出任何代码,因为生成的字节码根据所涉及对象的类型而不同。
所有这些检查都需要时间,最重要的是,即使对于最简单的程序,编译器也必须从标准库中加载大量类定义。
相比之下,Python 字节码编译器只需要解析行,就可以立即生成代码,无需查看额外的模块。在 Python 中,代码将被编译为:
Python 编译器并不关心这些查找中的一些是否在运行时失败。
另一个重要的区别是 Java 编译器完全用 Java 编写,并在运行时编译为机器代码,而大部分 CPython 实现是提前编译的 C 代码。这意味着与 Python 相比,Java 存在一些“冷启动”问题。
更新:从 Java 9 开始,您可以直接从源代码运行 Java 程序,而无需将其编译为字节码。运行一个简单的“hello world”程序可以让您了解通过提前将 Java 编译为字节码可以节省多少,即使对于一个简单的程序也是如此:
time python hello.py.time java Hello.javatime java Hello免责声明:没有遵循科学方法或进行统计分析,所以对此持保留态度。测试环境:Python 3.8.5,Java 11.0.8,Fedora 32,Intel i7 8750H CPU
你好.py:
System.out.println("Hello World!");
你好.java:
print("hello world")
| 归档时间: | 
 | 
| 查看次数: | 808 次 | 
| 最近记录: |