64

我才意识到这样做

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 关键字那样内联这样的函数?

4

6 回答 6

38

是否可以像在 C 中使用宏或使用 inline 关键字那样内联这样的函数?

不。在到达这个特定指令之前,Python 解释器甚至不知道是否有这样的函数,更不用说它做了什么。

正如评论中所指出的,PyPy将自动内联(上面仍然成立 - 它“简单地”在运行时生成一个优化版本,从中受益,但在它失效时会中断它),尽管在这种特定情况下没有帮助因为在 PyPy 上实现 NumPy 是不久前才开始的,直到今天还不是 beta 级别。但底线是:不要担心 Python 中这一级别的优化。实现自己优化或不优化,这不是你的责任。

于 2011-06-22T15:31:48.203 回答
28

不完全是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 中实现此类优化器所涉及的复杂性感兴趣的人也可能想看看:

于 2016-10-26T11:53:03.930 回答
10

我同意其他所有人的观点,这样的优化只会让你对 CPython感到痛苦,如果你关心性能,你应该考虑 PyPy(尽管我们的 NumPy 可能太不完整而没有用处)。但是我不同意并说您可以关心 PyPy 上的此类优化,而不是像所说的那样 PyPy 自动执行此优化,但是如果您对 PyPy 非常了解,您真的可以调整您的代码以使 PyPy 发出您想要的程序集,并不是说你几乎永远都需要。

于 2011-06-24T03:28:00.037 回答
7

实际上计算起来可能更快,例如:

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代码的真正有效的方式。

于 2011-06-22T16:58:35.963 回答
7

不。

最接近 C 宏的是可以包含在 makefile 中的脚本(awk 或其他),它用长格式替换 python 脚本中的特定模式,如 abs(x)**2。

于 2011-06-22T15:09:11.873 回答
1

您可以尝试使用lambda

abs2 = lambda x : x.real*x.real+x.imag*x.imag

然后通过以下方式调用它:

y = abs2(x)
于 2019-06-24T13:38:21.923 回答