我才意识到这样做
x.real*x.real+x.imag*x.imag
比做快三倍
abs(x)**2
其中 x 是一个 numpy 复数数组。为了代码可读性,我可以定义一个函数
def abs2(x):
return x.real*x.real+x.imag*x.imag
它仍然比 abs(x)**2 快得多,但它是以函数调用为代价的。是否可以像在 C 中使用宏或使用 inline 关键字那样内联这样的函数?
我才意识到这样做
x.real*x.real+x.imag*x.imag
比做快三倍
abs(x)**2
其中 x 是一个 numpy 复数数组。为了代码可读性,我可以定义一个函数
def abs2(x):
return x.real*x.real+x.imag*x.imag
它仍然比 abs(x)**2 快得多,但它是以函数调用为代价的。是否可以像在 C 中使用宏或使用 inline 关键字那样内联这样的函数?
是否可以像在 C 中使用宏或使用 inline 关键字那样内联这样的函数?
不。在到达这个特定指令之前,Python 解释器甚至不知道是否有这样的函数,更不用说它做了什么。
正如评论中所指出的,PyPy将自动内联(上面仍然成立 - 它“简单地”在运行时生成一个优化版本,从中受益,但在它失效时会中断它),尽管在这种特定情况下没有帮助因为在 PyPy 上实现 NumPy 是不久前才开始的,直到今天还不是 beta 级别。但底线是:不要担心 Python 中这一级别的优化。实现自己优化或不优化,这不是你的责任。
不完全是OP所要求的,但很接近:
Inliner 内联 Python 函数调用。这篇博文的概念证明
from inliner import inline @inline def add_stuff(x, y): return x + y def add_lots_of_numbers(): results = [] for i in xrange(10): results.append(add_stuff(i, i+1))
在上面的代码中,add_lots_of_numbers 函数被转换为:
def add_lots_of_numbers(): results = [] for i in xrange(10): results.append(i + i + 1)
任何对这个问题以及在 CPython 中实现此类优化器所涉及的复杂性感兴趣的人也可能想看看:
我同意其他所有人的观点,这样的优化只会让你对 CPython感到痛苦,如果你关心性能,你应该考虑 PyPy(尽管我们的 NumPy 可能太不完整而没有用处)。但是我不同意并说您可以关心 PyPy 上的此类优化,而不是像所说的那样 PyPy 自动执行此优化,但是如果您对 PyPy 非常了解,您真的可以调整您的代码以使 PyPy 发出您想要的程序集,并不是说你几乎永远都需要。
实际上计算起来可能更快,例如:
x.real** 2+ x.imag** 2
因此,函数调用的额外成本可能会减少。让我们来看看:
In []: n= 1e4
In []: x= randn(n, 1)+ 1j* rand(n, 1)
In []: %timeit x.real* x.real+ x.imag* x.imag
10000 loops, best of 3: 100 us per loop
In []: %timeit x.real** 2+ x.imag** 2
10000 loops, best of 3: 77.9 us per loop
并将计算封装在一个函数中:
In []: def abs2(x):
..: return x.real** 2+ x.imag** 2
..:
In []: %timeit abs2(x)
10000 loops, best of 3: 80.1 us per loop
无论如何(正如其他人指出的那样)这种微优化(为了避免函数调用)并不是编写python代码的真正有效的方式。
不。
最接近 C 宏的是可以包含在 makefile 中的脚本(awk 或其他),它用长格式替换 python 脚本中的特定模式,如 abs(x)**2。
您可以尝试使用lambda
:
abs2 = lambda x : x.real*x.real+x.imag*x.imag
然后通过以下方式调用它:
y = abs2(x)