这是非常糟糕的微优化,但我只是好奇。它通常不会在“真实”世界中产生影响。
所以我正在使用 compile()
编译一个函数(什么都不做),然后对该代码调用 exec
并获取对我编译的函数的引用。然后我执行它几百万次并计时。然后用局部函数重复它。为什么动态编译的函数仅调用就慢了大约 15%(在 python 2.7.2 上)?
import datetime
def getCompiledFunc():
cc = compile("def aa():pass", '<string>', 'exec')
dd = {}
exec cc in dd
return dd.get('aa')
compiledFunc = getCompiledFunc()
def localFunc():pass
def testCall(f):
st = datetime.datetime.now()
for x in xrange(10000000): f()
et = datetime.datetime.now()
return (et-st).total_seconds()
for x in xrange(10):
lt = testCall(localFunc)
ct = testCall(compiledFunc)
print "%s %s %s%% slower" % (lt, ct, int(100.0*(ct-lt)/lt))
我得到的输出是这样的:
1.139 1.319 15% slower
最佳答案
dis.dis() 函数显示每个版本的代码对象是相同的:
aa
1 0 LOAD_CONST 0 (None)
3 RETURN_VALUE
localFunc
10 0 LOAD_CONST 0 (None)
3 RETURN_VALUE
所以区别在于函数对象。我比较了每个字段(func_doc、func_closure 等),不同的是 func_globals。换句话说,localFunc.func_globals != compiledFunc.func_globals
。
提供你自己的字典而不是内置的全局变量是有代价的(前者必须在每次调用时创建堆栈帧时查找,而后者可以由已经知道的 C 代码直接引用关于默认的内置全局字典)。
这很容易验证,只需将代码中的 exec 行更改为:
exec cc in globals(), dd
随着那个的改变,时间差异消失了。
谜底揭晓!
关于python - 为什么 python 中的空函数调用对于动态编译的 python 代码要慢 15% 左右,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8191390/