Python - 及时克服导入
Posted
技术标签:
【中文标题】Python - 及时克服导入【英文标题】:Python - Overcome import in timeit 【发布时间】:2018-06-01 05:34:44 【问题描述】:我最近注意到timeit
python 模块的以下内容:
在我的机器上:
from timeit import Timer
t = Timer(stmt='a = 2**3**4')
print("This took :.3fs to execute.".format(t.timeit()))
将产生:
这需要 0.017 秒来执行。
另一方面写一个文件test.py:
#!/usr/bin/env python3
a = 2**3**4
并调用:
from timeit import Timer
t = Timer(stmt='import test')
print("This took :.3fs to execute.".format(t.timeit()))
将产生:
这需要 0.126 秒来执行。
我想知道如何在不更改文件本身的情况下测试test.py
的执行时间。我如何才能解决导入文件的问题(因此会浪费时间)。
【问题讨论】:
***.com/a/24105845/650884 如果是第一次调用import test
,python 将忙于创建“test.pyc”并需要更长的时间。后续导入应该会快一些。
@Aaron:除了后续的导入根本不会导入任何东西(他们经历了一堆导入复杂的过程,最终从sys.modules
拉出缓存的模块,这不会重新运行模块完全)。
【参考方案1】:
您将获得的最接近的方法是将compile
与exec
一起使用。如果您打算以 .pyc 文件的形式运行,请不要在计时的内容中包含编译语句。
# time as if executing:" >python test.pyc " from terminal
# (importing test.py will typically automatically generate the .pyc file automatically)
t = Timer(stmt='exec(code_object)',
setup='code_object = compile(open("test.py").read(), "test.py", "exec")')
# time as if executing:" >python test.py " from terminal
t = Timer(stmt='exec(compile(open("test.py").read(), "test.py", "exec"))')
这应该让您接近从终端调用脚本的实际时间。这并不能消除开销,因为调用脚本的开销是真实存在的,并且会在现实世界中观察到。
如果您使用的是基于 linux 的系统,您也可以从终端调用 >time test.py
。
【讨论】:
@StefanPochmann 对不起,愚蠢的错别字。不去想我在做什么。见编辑 好的,现在它可以工作了,但是......大约需要 0.35 秒,而 OP 的方式只需要 0.15 秒。当您测试它时,它真的对您更快吗?这次你做了测试,对吧? :-P 我想给一个脚本计时,只要我把它全部放在引号中并把它作为stmt
放在timeit
中。 >time test.py
总是打印更多时间,因为包含了 python 启动。我将如何解决这个问题?我想测试一些代码...code...
,就好像我使用了print(Timer.timeit(stmt='code'))
。
也许你也想看看我的next question
@StefanPochmann 这不是更快,它是真实世界的代表【参考方案2】:
当你写作时,你的测量存在一个问题,你没有测量你认为你正在测量的东西:
t = Timer(stmt= 'a = 2**3**4')
您正在测量绑定时间!看:
>>> Timer(stmt='a = 10**5**4').timeit(100000)
0.0064544077574026915
>>> Timer(stmt='a = 2**3**4').timeit(100000)
0.006511381058487586
时间几乎相同,但计算 10**5**4
比 2**3**4
要长一些。 2**3**4
只计算一次,在编译代码时,这称为“常量折叠”,Python 在编译源代码期间执行的一些优化。
比较这两个结果:
>>> Timer(stmt= 'a = 2**3**4').timeit(100000)
0.00628656749199763
>>> Timer(stmt= 'a = x**y**z', setup='(x,y,z)=(2,3,4)').timeit(100000)
0.18055968312580717
但这种加速并不是免费的。有两点:
-
编译时间增加
.pyc
文件大小增加(因为此值存储在 .pyc
文件中)
假设我有两个文件:
#foo1.py
a = 10**7**7
#foo2.py
x,y,z =(10,7,7)
a = x**y**z
如果我用python -m py_compile foo1.py foo2.py
编译它们,我机器上.pyc
文件的大小将为:
foo1.cpython-36.pyc
- 364 882 字节
foo2.cpython-36.pyc
- 150 字节
【讨论】:
这真的很有趣,但我不太明白这与我的导入语句有什么关系?我在想,当我导入test.py
时,已经存在一个包含常量的test.pyc
,因此代码应该比动态生成它更快(例如在命令行中),而实际上使用导入更慢.
也许你也想看看我的next question以上是关于Python - 及时克服导入的主要内容,如果未能解决你的问题,请参考以下文章
克服 Python 2.3 中的 os.system() 限制