编译为字节码,Java 与 Python。造成所用时间差异的原因是什么? [关闭]

2023-12-03

Java 和 python(仅谈论 CPython)都分别解释为 Java 和 CPython 字节码。然后,两个字节码都由各自的虚拟机(JVM 和 Cpython VM)解释。 (这里我忽略了 JIT 编译部分,它在 10K 运行后启动。)

我对此有两个问题:

  1. 为什么 Java 编译为 java 字节码比 python 花费更多时间?在 java 中,编译是一个显式步骤,而在 python 中,编译是在运行时发生的。
  2. 为什么在第一次运行时,Python 的第一次运行和第 n 次运行之间没有明显的差异,因为在第一次运行时,CPython 字节码的编译完成并缓存在 .pyc 文件中,该文件在所有后续运行中使用。在Python中,这个字节码编译真的是一个几乎零成本的任务吗?

尽管它在运行时发挥着重要作用,但我认为静态类型与动态类型在编译期间不应该扮演太大的角色,并且不应该是这种计时差异的唯一原因。另外,我认为在这两种实现中,在字节码生成期间都进行了一些优化。

我在这里缺少什么吗? (我没有太多 Java 工作经验。)

Update:

我实际上对 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 中,代码将被编译为:

  • 从当前范围(LOAD_NAME)查找“系统”对象
  • 从系统中查找“out”属性(LOAD_ATTR)
  • 从“out”查找“println”(LOAD_METHOD)
  • 生成代码来调用它(CALL_METHOD)

Python 编译器并不关心其中一些查找在运行时是否失败。

另一个重要的区别是 Java 编译器完全用 Java 编写,并在运行时编译为机器代码,而 CPython 的大部分实现是提前编译的 C 代码。这意味着与Python相比,Java存在一点“冷启动”问题。

Update:从 Java 9 开始,您可以直接从源代码运行 java 程序,而无需将其编译为字节代码。运行一个简单的“hello world”程序可以让您了解通过提前将 Java 编译为字节代码可以节省多少成本,即使对于一个简单的程序也是如此:

  • 根据测量,Python 程序的运行时间为 45-50 毫秒time python hello.py.
  • Java程序无需提前编译为字节码根据测量,运行时间为 350-400 毫秒time java Hello.java
  • 编译为字节码后的 Java 程序运行时间为 70-80 毫秒,测量结果为time java Hello

免责声明:没有遵循科学方法或进行统计分析,所以对此持保留态度。测试环境:Python版本3.8.5、Java版本11.0.8、Fedora 32、Intel i7 8750H CPU

你好.py:

print("hello world")

你好.java:

public class Hello {
    public static void main(String[] args) {
        System.out.println("Hello world");
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

编译为字节码,Java 与 Python。造成所用时间差异的原因是什么? [关闭] 的相关文章

随机推荐

  • 如何验证 Codeigniter 中组合的多个字段?

    有没有一种创造性且简单的方法可以同时检查多个表单字段 我有一个带有动态生成字段的表单 每个字段都有一个唯一的 ID 问题是提交时不需要填写所有字段 但在提交之前至少必须填写一个字段 有没有办法在 Codeigniter 中做到这一点 或者我
  • 不存在 ID 为 *id* 的消息

    我正在尝试列出通过 mandrill API 发送的电子邮件 我可以通过打电话列出它们https mandrillapp com api 1 0 messages search json 这给了我一个列表 其中包含一堆已发送的消息以及一个
  • 保留通用变量之间的类型限制

    假设我们有一些类有一个重要的泛型变量T另一个类有两个字段 一个包含 一个不包含 class Wrapper
  • C++ 调用非默认构造函数作为成员[重复]

    这个问题在这里已经有答案了 假设我有一个类 A 和一个类 B B 用作 A 中的成员 B 没有默认构造函数 但需要参数 class B B int i class A B m B A m B 17 this gives an error 我
  • 当应该使用 String 时,groupingBy 将键的对象返回为 Map

    假设我有一个品牌对象列表 POJO 包含返回字符串的 getName 我想建立一个Map
  • R 记录脚本的显示名称

    这是我当前问题的一个原子示例 目前我有一个包含多个 R 脚本的项目 全部位于名为 DIR 的同一目录中 我在 DIR 中有一个主脚本 它获取所有 R 文件 并包含一个基本配置 basicConfig 我在 DIR 中使用了两个脚本 dog
  • C++:重复执行 do while 循环

    我对这个超级新手问题感到非常抱歉 但我一生都无法理解如何重复 do while 循环 我将 while 循环更改为 do while 循环 现在我不知道如何让它询问 您想重复 Y 还是 N 有什么解释吗 我读过各种完成 do while 循
  • 如何使用 jQuery 访问多维 JSON 数组中的值

    因此 我使用 getJSON 获取多维 JSON 数组 并且想要访问数组中的值 但无法访问比数组中第一个元素更长的值 producers producer id 1 name Em u00e5mejeriet address Grenv u
  • 异步承诺返回函数的同步与异步执行

    当制作返回承诺的异步函数时 在每个实现中我都看到了这种做法 function asyncFunction return new Promise resolve reject gt the function code if condition
  • WPF WebBrowser 控件中的持久 cookie?

    我正在使用 WPF WebBrowser 在应用程序内显示在线帮助 只是一些小网页 其中一些页面使用 cookie 仅在页面被查看的前几次显示项目 这是 为什么不尝试 X 类型的事情 但是 由于某种原因 cookie 似乎无法在 WebBr
  • 模糊效果 CSS3 Firefox(linux)

    如果用户未注册 我试图在我的相册上获得模糊效果 我明白了 但仅限于 chrome 在我的 Firefox 14 0 1 linux 中我无法让它工作 我的html模板 我在django下开发 h2 Gallerie h2 ul class
  • matplotlib 3D 图,plot_surface 黑色

    我有以下数据 https www dropbox com s u7ee09chaixw5vb draw dl 0 它是使用python3中的pickle保存的 它只是一个二维的python列表 形式为z 我使用以下代码绘制 3D 图形 但它
  • 命名空间的自定义配置节问题的智能感知

    我刚刚滚动了一个自定义配置部分 为 Intellisense 创建了一个随附的架构文档 并将其添加到 Web config 的 Schemas 属性中迈克尔 斯图姆的回答另一个类似的问题 不幸的是 可能由于我以有限的知识手工创建 XSD I
  • 如何使用字符串设置 jQueryUI Datepicker 的 minDate/maxDate?

    jQueryUI 日期选择器文档指出可以使用 当前日期格式中的字符串 来设置 minDate 选项 所以我尝试了以下方法来初始化日期选择器 input date datepicker minDate 01 01 2010 maxDate 1
  • 融合具有列模式的 data.table

    我有一个data table看起来像这样 id A1g hi A2g hi A3g hi A4g hi 1 2 3 4 5 我想melt这张表看起来像这样 id time hi 1 1 2 1 2 3 1 3 4 1 4 5 我尝试过这样的
  • 连接 __contains 和 __in 最简单的方法是什么?

    我正在做标签搜索功能 用户可以观察很多标签 我将所有标签都放在一个元组中 现在我想找到包含列表中至少一个标签的所有文本 象征性 text contains in asd dsa 我唯一的想法是循环 例如 q text objects all
  • “分段错误”与“运行时”错误? [复制]

    这个问题在这里已经有答案了 考虑一下这段代码片段 char str hellow Ghost str 0 z printf s str 这是一个分段错误 它还会出现运行时内存错误吗 我对分段错误的理解是 当您访问不属于您的内存时出现分段错误
  • Spring Boot 无法拦截执行器访问

    在Spring Boot 2 1 6版本中无法拦截访问执行器请求现在我有一个全局拦截器 Component public class ServiceFilter implements HandlerInterceptor log4j sta
  • 提升以固定单子变压器堆栈的“内部”

    假设我有一个IO Int包裹在一个StateT MyState 那么我的值为State MyState Int我想在堆叠单子中使用它 我如何在这种内在的意义上提升它 我已经知道使用lift or liftIO如果我得到与内部兼容的东西 我只
  • 编译为字节码,Java 与 Python。造成所用时间差异的原因是什么? [关闭]

    Closed 这个问题需要多问focused 目前不接受答案 Java 和 python 仅谈论 CPython 都分别解释为 Java 和 CPython 字节码 然后 两个字节码都由各自的虚拟机 JVM 和 Cpython VM 解释