python虚拟机直接加载字节码运行程序_如果pythonvm执行字节码,那么非导入模块的字节码在哪里?...

博主深入探究Python如何在导入时处理pyc文件,发现即使禁用pyc生成,仍会在必要时动态编译。实验显示,Python在无pyc时直接解析源码,而在源码不存在或已删除时重新编译。这一行为引发关于效率与警告的讨论。
摘要由CSDN通过智能技术生成

有趣。。。我做的第一件事就是打电话给help$ python help

usage: python [option] ... [-c cmd | -m mod | file | -] [arg] ...

Options and arguments (and corresponding environment variables):

-B : don't write .py[co] files on import; also PYTHONDONTWRITEBYTECODE=x

...

我看到的第一个选项是在导入时禁用自动pyc和pyo文件生成,尽管这可能导致了它的字母顺序。在

让我们做些测试

^{pr2}$

所以它只在导入时生成pyc文件。在

现在为了检查正在使用哪些文件,我将使用类似于linux truss的OS X dtruss来执行完整的跟踪。。。在$ echo '#!/bin/sh

python test.py' > test.sh

$ chmod a+x test.sh

$ sudo dtruss -a ./test.sh 2>&1 | grep "test.py*"

975/0x5713: 244829 6 3 read(0x3, "#!/bin/sh \npython test.py\n\b\0", 0x50) = 26 0

975/0x5713: 244874 4 2 read(0xFF, "#!/bin/sh \npython test.py\n\b\0", 0x1A) = 26 0

977/0x5729: 658694 6 2 readlink("test.py\0", 0x7FFF5636E360, 0x400) = -1 Err#22

977/0x5729: 658726 10 6 getattrlist("/Users/samyvilar/test.py\0", 0x7FFF7C0EE510, 0x7FFF5636C6E0 = 0 0

977/0x5729: 658732 3 1 stat64("test.py\0", 0x7FFF5636DCB8, 0x0) = 0 0

977/0x5729: 658737 5 3 open_nocancel("test.py\0", 0x0, 0x1B6) = 3 0

977/0x5729: 658760 4 2 stat64("test.py\0", 0x7FFF5636E930, 0x1) = 0 0

977/0x5729: 658764 5 2 open_nocancel("test.py\0", 0x0, 0x1B6) = 3 0

从外观上看,python甚至都不碰它测试.pyc完全归档!在$ echo '#!/bin/sh

python -c "import test"' > test.sh

$ chmod a+x test.sh

$ sudo dtruss -a ./test.sh 2>&1 | grep "test.py*"

$ sudo dtruss -a ./test.sh 2>&1 | grep "test.py*"

1028/0x5d74: 654642 8 5 open_nocancel("test.py\0", 0x0, 0x1B6) = 3 0

1028/0x5d74: 654683 8 5 open_nocancel("test.pyc\0", 0x0, 0x1B6) = 4 0

$

很有意思,看起来像是打开了测试.py那么测试.pyc在

当我们删除pyc文件时会发生什么。在$ rm test.pyc

$ sudo dtruss -a ./test.sh 2>&1 | grep "test.py*"

1058/0x5fd6: 654151 7 4 open_nocancel("/Users/samyvilar/test.py\0", 0x0, 0x1B6) = 3 0

1058/0x5fd6: 654191 6 3 open_nocancel("/Users/samyvilar/test.pyc\0", 0x0, 0x1B6) = -1 Err#2

1058/0x5fd6: 654234 7 3 unlink("/Users/samyvilar/test.pyc\0", 0x1012B456F, 0x1012B45E0) = -1 Err#2

1058/0x5fd6: 654400 171 163 open("/Users/samyvilar/test.pyc\0", 0xE01, 0x81A4) = 4 0

它首先打开测试.py然后它试图打开测试.pyc它返回一个错误,然后调用unlink并再次生成pyc文件。。。有意思,我以为可以查到。在

如果我们删除原始的py文件呢。在$ sudo dtruss -a ./test.sh 2>&1 | grep "test.py*"

1107/0x670d: 655064 4 1 open_nocancel("test.py\0", 0x0, 0x1B6) = -1 Err#2

1107/0x670d: 655069 8 4 open_nocancel("test.pyc\0", 0x0, 0x1B6) = 3 0

怪不得它打不开测试.py但它仍然在继续,直到今天,我还不确定这是否真的“好”python应该发出某种警告,我已经被这个烧坏了好几次,不小心删除了我的文件,运行了我的测试,当它们通过时,我感到松了一口气,但当我似乎找不到的时候,我开始流汗源代码!在

在这个测试之后,我们假设python只在调用时直接使用pyc文件,比如python test.pyc或者在导入时间接使用pyc文件,否则它似乎不使用它们。在

假设CPythons编译器的设计速度相当快,它不做太多的类型检查,它可能会生成非常高级别的字节码,所以大部分的工作负载实际上是由虚拟机完成的。。。它可能一次性完成一个单一的过程,lexing->compiler->字节码,它每次都这样做,它从命令行读取python文件,或者导入时没有pyc文件,在这种情况下,它会创建它。在

这可能就是为什么其他一些实现更快,因为它们需要更多的编译时间,但生成的字节码更原始,可以很好地优化。在

建立一个虚拟机来高效地进行纯解释是非常困难的。。。在

这一切都是关于平衡的,你的字节码越强大,你的编译器就越简单,但你的虚拟机就越复杂和缓慢,反之亦然。。。在

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值