为什么预编译pyc文件不能给出预期的结果?

时间:2017-07-11 14:50:47

标签: python python-3.x pyc

我遇到的情况我实在无法解释:我在一个带有只读文件系统的系统上运行Python脚本,并为所有Python模块生成预先生成的.pyc文件,然后我再次运行它重新安装文件系统可写。第二次运行后,脚本执行得更快。

这并没有让我感到惊讶 - 也许首先没有正确生成预先生成的.pyc文件。在第二次运行时,它们将被重新生成并被写入(位于__pycache__文件夹中)并在第三次运行时重新使用。

注意: 我正在尝试的脚本只是导入一些本机Python模块(sysosargparse等) - 没有其他与性能相关的代码。因此,每次运行之间唯一的性能相关差异是预编译的字节代码(正如我所能想到的)。 机器上没有运行其他相关进程。

奇怪的是所有 __pycache__文件夹的内容根本不会改变 。我已经复制了整个/usr/lib/python3.5文件夹和包含我的脚本的文件夹之后重新安装并且没有一点区别

Python在哪里存储运行速度更快所需的信息?为什么.pyc文件(或它们的时间戳!)没有改变?

详细

我目前正在尝试预先编译Python脚本,然后将它们部署到带有RO文件系统的嵌入式目标上,结果不符合预期(无法观察时间上的任何差异)。

以下是我正在做的观察不良行为的事情:

  • 登录目标(rootfs已安装RO)
  • 运行脚本:time myscript.py,运行 5.7秒
  • 运行脚本:time myscript.py,运行 5.7秒
  • ...(可以重复,结果总是一样的)
  • scp /usr/lib/python3.5/site-packages的内容和包含myscript.py的文件夹到名为before
  • 的文件夹
  • 更新:捕获所有.pyc个文件的所有权限和时间戳
  • 重新安装RW:mount -o remount,rw /
  • 运行脚本:time myscript.py,运行时间略多于 5.7秒
  • 运行脚本:time myscript.py,运行 1.79秒
  • 运行脚本:time myscript.py,运行 1.79秒
  • ...(可以重复,结果总是一样的)
  • scp /usr/lib/python3.5/site-packages的内容和包含myscript.py的文件夹到名为after
  • 的文件夹
  • 更新:再次捕获所有.pyc个文件的所有权限和时间戳
  • 比较我怀疑现在包含已修改.pyc的文件夹 - 文件:

    diff -r before after

    没有差异

  • 更新:比较之前捕获的所有时间戳和权限 - 无差异

我还尝试手动修改其中一个复制的.pyc文件,以检查diff是否真的比较二进制文件,但是按预期工作。

重启后,系统在写入缓存文件时也会按预期运行(脚本运行速度很快)。

对于那些不相信我的人:

root@machine:/data# cat myscript.py 
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import argparse
import logging
import signal
import sys, os, shutil

if __name__ == '__main__':
    print('hello')

root@machine:/data# time ./myscript.py 
hello
real    0m5.756s, user  0m4.326s, sys   0m0.773s

root@machine:/data# time ./myscript.py 
hello
real    0m5.740s, user  0m4.289s, sys   0m0.797s

root@machine:/data# mount -o remount,rw /

root@machine:/data# time ./myscript.py 
hello
real    0m6.005s, user  0m4.374s, sys   0m0.845s

root@machine:/data# time ./myscript.py 
hello
real    0m1.789s, user  0m1.283s, sys   0m0.288s

root@machine:/data# time ./myscript.py 
hello
real    0m1.787s, user  0m1.287s, sys   0m0.284s

(我缩短了一些输出,但数字是正确的)

(非常奇怪)更新:

要跟踪所有.pyc个文件的时间戳,我在之前运行以下命令重新运行myscript.py之后:< / p>

find /usr/lib/python3.5/site-packages/ -name *.pyc -exec stat -t {} \; > file-details-before/after

结果是:file-details-beforefile-details-after 完全相同!内容看起来像这样(两种情况都相同):

...
/usr/lib/python3.5/site-packages/psutil/__pycache__/_psosx.cpython-35.pyc 10676 24 81a4 0 0 e 2221 1 0 0 1499781288 1499555909 1499781288 4096
/usr/lib/python3.5/site-packages/psutil/__pycache__/_psbsd.cpython-35.pyc 12047 24 81a4 0 0 e 2223 1 0 0 1499781288 1499555909 1499781288 4096
/usr/lib/python3.5/site-packages/psutil/__pycache__/_compat.cpython-35.pyc 8393 24 81a4 0 0 e 2222 1 0 0 1499781288 1499555910 1499781288 4096
/usr/lib/python3.5/site-packages/psutil/__pycache__/_psmswindows.cpython-35.pyc 14488 32 81a4 0 0 e 2227 1 0 0 1499781288 1499555910 1499781288 4096
/usr/lib/python3.5/site-packages/psutil/__pycache__/_pslinux.cpython-35.pyc 28030 56 81a4 0 0 e 2224 1 0 0 1499781288 1499555909 1499781288 4096
/usr/lib/python3.5/site-packages/psutil/__pycache__/__init__.cpython-35.pyc 37069 80 81a4 0 0 e 2220 1 0 0 1499781288 1499555910 1499781288 4096
/usr/lib/python3.5/site-packages/psutil/__pycache__/_psposix.cpython-35.pyc 3069 8 81a4 0 0 e 2219 1 0 0 1499781288 1499555909 1499781288 4096
/usr/lib/python3.5/site-packages/psutil/__pycache__/error.cpython-35.pyc 2557 8 81a4 0 0 e 2226 1 0 0 1499781288 1499555910 1499781288 4096
/usr/lib/python3.5/site-packages/psutil/__pycache__/_common.cpython-35.pyc 6188 16 81a4 0 0 e 2225 1 0 0 1499781288 1499555909 1499781288 4096
...

.pyc个文件的数量,其权限和时间戳相等,即diff file-details-before file-details-after没有显示差异。

监测:

在使用可写文件系统重新运行之前:

time python3 -m cProfile -s cumtime ./myscript.py
hello
         11530 function calls (11346 primitive calls) in 2.423 seconds

   Ordered by: cumulative time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
     19/1    0.020    0.001    2.423    2.423 {built-in method builtins.exec}
        1    0.001    0.001    2.423    2.423 myscript.py:4(<module>)
     21/4    0.004    0.000    2.422    0.605 <frozen importlib._bootstrap>:966(_find_and_load)
     21/4    0.002    0.000    2.418    0.605 <frozen importlib._bootstrap>:939(_find_and_load_unlocked)
     21/4    0.008    0.000    2.369    0.592 <frozen importlib._bootstrap>:659(_load_unlocked)
     16/4    0.003    0.000    2.353    0.588 <frozen importlib._bootstrap_external>:656(exec_module)
     42/8    0.010    0.000    2.319    0.290 <frozen importlib._bootstrap>:214(_call_with_frames_removed)
       16    0.009    0.001    1.815    0.113 <frozen importlib._bootstrap_external>:726(get_code)
       16    0.001    0.000    1.700    0.106 <frozen importlib._bootstrap_external>:718(source_to_code)
       16    1.689    0.106    1.689    0.106 {built-in method builtins.compile}
        1    0.003    0.003    0.687    0.687 __init__.py:24(<module>)
...
real    0m7.611s, user  0m5.861s, sys   0m0.877s

之后:

time python3 -m cProfile -s cumtime ./myscript.py
hello
         11050 function calls (10878 primitive calls) in 0.730 seconds

   Ordered by: cumulative time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
     19/1    0.024    0.001    0.730    0.730 {built-in method builtins.exec}
        1    0.001    0.001    0.730    0.730 myscript.py:4(<module>)
     21/4    0.005    0.000    0.729    0.182 <frozen importlib._bootstrap>:966(_find_and_load)
     21/4    0.002    0.000    0.725    0.181 <frozen importlib._bootstrap>:939(_find_and_load_unlocked)
     21/4    0.005    0.000    0.684    0.171 <frozen importlib._bootstrap>:659(_load_unlocked)
     16/4    0.004    0.000    0.677    0.169 <frozen importlib._bootstrap_external>:656(exec_module)
     26/4    0.001    0.000    0.638    0.160 <frozen importlib._bootstrap>:214(_call_with_frames_removed)
        1    0.003    0.003    0.313    0.313 __init__.py:24(<module>)
        1    0.002    0.002    0.203    0.203 shutil.py:5(<module>)
       21    0.007    0.000    0.201    0.010 <frozen importlib._bootstrap>:879(_find_spec)
       19    0.001    0.000    0.187    0.010 <frozen importlib._bootstrap_external>:1130(find_spec)
...
real    0m3.102s, user  0m2.196s, sys   0m0.448s

0 个答案:

没有答案