为什么列表乘法这么快? [英] Why is list multiplication so fast?

查看:62
本文介绍了为什么列表乘法这么快?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在创建列表时,我认为建议尽可能使用理解,因为它是最快的.但是你瞧.

When creating a list, I thought comprehension is recommended whenever possible as it is fastest. But lo and behold.

In [1]: %timeit -n1000 [0]*1000000
1000 loops, best of 3: 2.3 ms per loop

In [2]: %timeit -n1000 [0 for _ in range(1000000)]
1000 loops, best of 3: 27.1 ms per loop

In [3]: a = np.zeros(1000000, dtype=int)

In [4]: %timeit -n1000 a.tolist()
1000 loops, best of 3: 7.93 ms per loop

即使 numpy.ndarray.tolist 也跟不上乘法.这是为什么?

Even numpy.ndarray.tolist can't keep up with multiplication. Why is that?

推荐答案

dis 模块对于比较前两种方法很有用.

The dis module is useful for comparing the first two methods.

def list_mult():
    return [0]*1000000

dis.dis(list_mult)
#  2           0 LOAD_CONST               1 (0)
#              3 BUILD_LIST               1
#              6 LOAD_CONST               2 (1000000)
#              9 BINARY_MULTIPLY     
#             10 RETURN_VALUE        

这里使用了 BINARY_MULTIPLY 指令.另一方面...

Here, the BINARY_MULTIPLY instruction is used. On the other hand...

def list_range():
    return [0 for _ in range(1000000)]

dis.dis(list_range)
# 2           0 BUILD_LIST               0
#             3 LOAD_GLOBAL              0 (range)
#             6 LOAD_CONST               1 (1000000)
#             9 CALL_FUNCTION            1
#            12 GET_ITER            
#       >>   13 FOR_ITER                12 (to 28)
#            16 STORE_FAST               0 (_)
#            19 LOAD_CONST               2 (0)
#            22 LIST_APPEND              2
#            25 JUMP_ABSOLUTE           13
#       >>   28 RETURN_VALUE    

此函数显式构造一个循环,然后在每次迭代中加载 0 并将其附加到工作列表中.这会慢很多.

This function explicitly constructs a loop, and then loads 0 and appends it to the working list in each iteration. This is going to be a lot slower.

需要注意的是,这两种构造方法并不等价,尤其是当列表中的值是可变的时.例如,[object()] * 10 会给你一个包含 10 个相同对象的列表,而 [object() for _ in range(10)] 会给你给你一个包含 10 个不同对象的列表.

It should be noted that these two construction methods are not equivalent, particularly when the value inside the list is mutable. For example, [object()] * 10 will give you a list of 10 of the same object, while [object() for _ in range(10)] will give you a list of 10 distinct objects.

numpy 示例而言,此操作是 numpy 的最坏情况.构造和转换 numpy 数组有很多开销,因此矢量化操作可以很快(如注释中所述).

Regarding the numpy example, this operation is kind of the worst-case for numpy. There is a lot of overhead in constructing and converting numpy arrays so that the vectorized operations can be fast (as noted in the comments).

这篇关于为什么列表乘法这么快?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆