Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/346.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 使用for循环求和比使用reduce快?_Python_Performance - Fatal编程技术网

Python 使用for循环求和比使用reduce快?

Python 使用for循环求和比使用reduce快?,python,performance,Python,Performance,我想看看reduce比使用for循环进行简单的数值运算要快多少。以下是我发现的(使用标准timeit库): 再看一下: In [68]: timeit("1+2", setup) Out[68]: 0.04145693778991699 In [69]: timeit("add(1,2)", setup) Out[69]: 0.22807812690734863 这是怎么回事?显然,reduce的循环速度比for快,但函数调用似乎占主导地位。reduce版本不应该几乎完全在C中运行吗?在fo

我想看看reduce比使用for循环进行简单的数值运算要快多少。以下是我发现的(使用标准timeit库):

再看一下:

In [68]: timeit("1+2", setup)
Out[68]: 0.04145693778991699

In [69]: timeit("add(1,2)", setup)
Out[69]: 0.22807812690734863
这是怎么回事?显然,reduce的循环速度比for快,但函数调用似乎占主导地位。reduce版本不应该几乎完全在C中运行吗?在for循环版本中使用iadd(c,i)可以使其在约24秒内运行。为什么使用operator.add比+慢得多?我的印象是+和operator.add运行相同的C代码(我检查以确保operator.add不仅仅是在python中调用+或其他任何东西)

顺便说一句,仅使用sum运行约2.3秒

In [70]: print(sys.version)
2.7.1 (r271:86882M, Nov 30 2010, 09:39:13) 
[GCC 4.0.1 (Apple Inc. build 5494)]

这可能是复制参数和返回值(即“add(1,2)”)的开销,而不是简单地对数字文本进行操作。reduce(add,r)必须调用
add()
函数100次,因此,函数调用的开销增加了--reduce在每次迭代中使用
PyEval\u CallObject
调用
add

for (;;) {
    ...
    if (result == NULL)
        result = op2;
    else {
        # here it is creating a tuple to pass the previous result and the next
        # value from range(100) into func add():
        PyTuple_SetItem(args, 0, result);
        PyTuple_SetItem(args, 1, op2);
        if ((result = PyEval_CallObject(func, args)) == NULL)
            goto Fail;
    }
更新:回复评论中的问题

在Python源代码中键入
1+2
时,字节码编译器执行适当的加法,并用
3
替换该表达式:

f1 = lambda: 1 + 2
c1 = byteplay.Code.from_code(f1.func_code)
print c1.code

1           1 LOAD_CONST           3
            2 RETURN_VALUE         
如果添加两个变量
a+b
,编译器将生成字节码,加载这两个变量并执行二进制加法,这比调用函数执行加法要快得多:

f2 = lambda a, b: a + b
c2 = byteplay.Code.from_code(f2.func_code)
print c2.code

1           1 LOAD_FAST            a
            2 LOAD_FAST            b
            3 BINARY_ADD           
            4 RETURN_VALUE         
编辑:将零替换为数组乘法会大大缩短间距

from functools import reduce
from numpy import array, arange, zeros
from time import time

def add(x, y):
    return x + y

def sum_columns(x):
    if x.any():
        width = len(x[0])
        total = zeros(width)
    for row in x:
        total += array(row)
    return total

l = arange(3000000)
l = array([l, l, l])

start = time()
print(reduce(add, l))
print('Reduce took {}'.format(time() - start))

start = time()
print(sum_columns(l))
print('For loop took took {}'.format(time() - start))
让你失望几乎没有任何区别

0.0323061943054192
对于循环,取0.058577775955200195

旧:如果使用reduce按索引将NumPy数组添加到一起,它可能比for循环快

from functools import reduce
from numpy import array, arange
from time import time

def add(x, y):
    return x + y

def sum_columns(x):
    if x.any():
        width = len(x[0])
        total = array([0] * width)
    for row in x:
        total += array(row)
    return total

l = arange(3000000)
l = array([l, l, l])

start = time()
print(reduce(add, l))
print('Reduce took {}'.format(time() - start))

start = time()
print(sum_columns(l))
print('For loop took took {}'.format(time() - start))
由于

[      0       3       6 ..., 8999991 8999994 8999997]
Reduce took 0.024930953979492188
[      0       3       6 ..., 8999991 8999994 8999997]
For loop took took 0.3731539249420166

事实上,使用
sum
的运算速度快了4倍,这表明“应该有一种明显的方法来完成它”。@jsbbueno:没错,但我这样做是为了找出对序列进行一般数值计算的最快方法。在现实世界中,我当然会使用sum-to-sum:D,但我没有尝试mul,但我相信结果会相似。感谢您指出这一点!但是,它没有解释为什么原始的“1+2”比“add(1,2)”快5倍。事实上,在for中使用iadd时,reduce要比for快得多。为什么您的示例使用第三方软件包而不是内置的
dis
模块?没有特别的原因,只是我碰巧正在使用它。而不是
byteplay.code.from_code(f1.func\u code)
您可以使用
dis.dis(f1)
如果没有
biteplay
。在本例中,for循环速度如此之慢有几个原因。1) 使用
zero
而不是使用
数组([0]*宽度)
创建zero数组。2)
l
数组中很少有元素支持reduce函数,因为
for
循环开销太高。当你有6个或更多的元素时,for循环会更快。@zeroth它确实大大缩小了差距。它们在性能上与Python3.6和最新版本的numpy几乎相同。
[      0       3       6 ..., 8999991 8999994 8999997]
Reduce took 0.024930953979492188
[      0       3       6 ..., 8999991 8999994 8999997]
For loop took took 0.3731539249420166