Python中导入模块的优化
我正在阅读David Beazley的Python参考书,他指出:
例如,如果您正在执行大量的平方根操作,则使用'从数学导入sqrt'和'sqrt(x)'而不是输入'math.sqrt(x)'会更快。
和:
对于涉及大量使用方法或模块查找的计算,通过首先将要执行的操作放入局部变量来消除属性查找几乎总是更好。
我决定尝试一下:
第一()
def first():
from collections import defaultdict
x = defaultdict(list)
第二()
def second():
import collections
x = collections.defaultdict(list)
结果是:
2.15461492538
1.39850616455
这些优化对我来说可能并不重要。 但我很好奇,为什么Beazley写出的反面是真实的。 并注意到有1秒的差异,这是非常重要的,因为任务是微不足道的。
这是为什么发生?
更新:
我得到的时间如下:
print timeit('first()', 'from __main__ import first');
print timeit('second()', 'from __main__ import second');
from collections import defaultdict
并且import collections
应该在迭代的时序循环之外,因为您不会重复执行它们。
我猜想from
语法必须做更多的工作,即import
语法。
使用这个测试代码:
#!/usr/bin/env python
import timeit
from collections import defaultdict
import collections
def first():
from collections import defaultdict
x = defaultdict(list)
def firstwithout():
x = defaultdict(list)
def second():
import collections
x = collections.defaultdict(list)
def secondwithout():
x = collections.defaultdict(list)
print "first with import",timeit.timeit('first()', 'from __main__ import first');
print "second with import",timeit.timeit('second()', 'from __main__ import second');
print "first without import",timeit.timeit('firstwithout()', 'from __main__ import firstwithout');
print "second without import",timeit.timeit('secondwithout()', 'from __main__ import secondwithout');
我得到结果:
first with import 1.61359190941
second with import 1.02904295921
first without import 0.344709157944
second without import 0.449721097946
其中显示了重复进口的成本。
我会在first(.)
和second(.)
之间得到类似的比率,唯一的区别是时间是微秒级的。
我不认为你的时间安排是有用的。 尝试找出更好的测试用例!
更新:
FWIW,这里是一些支持David Beazley观点的测试。
import math
from math import sqrt
def first(n= 1000):
for k in xrange(n):
x= math.sqrt(9)
def second(n= 1000):
for k in xrange(n):
x= sqrt(9)
In []: %timeit first()
1000 loops, best of 3: 266 us per loop
In [: %timeit second()
1000 loops, best of 3: 221 us per loop
In []: 266./ 221
Out[]: 1.2036199095022624
所以first()
比second()
慢20%。
first()
不保存任何内容,因为仍然需要访问模块才能导入名称。
另外,你不给定你的计时方法,但给定函数名称,看起来first()
执行初始导入,因为模块必须被编译和执行,所以始终比后续导入要长。