3

目前我正在玩 Python 性能,试图加快我的程序(通常是那些计算启发式的程序)。我总是使用列表,尽量不进入numpy数组。

但最近我听说 Python 有8.7. array — Efficient arrays of numeric values,所以我想我会尝试那个。

我写了一段代码来测量 an array.count()vs. a list.count(),因为我在代码中的很多地方都使用了它:

from timeit import timeit
import array

a = array.array('i', range(10000))
l = [range(10000)]


def lst():
    return l.count(0)


def arr():
    return a.count(0)


print(timeit('lst()', "from __main__ import lst", number=100000))
print(timeit('arr()', "from __main__ import arr", number=100000))

我期待使用array. 好吧,这就是发生的事情:

> python main.py
0.03699162653848456
74.46420751473268

因此,根据timeit2013xlist.count()array.count(). 我绝对没想到。所以我搜索了 SO、python 文档等,我唯一发现的是数组中的对象必须首先包装到int-s 中,所以这可能会减慢速度,但我希望在创建一个array.array-instance,而不是在随机访问它时(我相信是这样.count()做的)。

那么问题在哪里?

难道我做错了什么?

或者也许我不应该使用标准数组而直接进入numpy.arrays?

4

1 回答 1

1

问题在哪里?

如上所述,初始测试不会将苹果与苹果进行比较:

更不用说range()它确实创建了一个 RAM 分配的数据结构,而xrange()类似于重新制定的对象(如下所示),一个生成器- 永远无法与任何智能 RAM 分配的数据结构相提并论。

>>> L_above_InCACHE_computing = [ range( int( 1E24 ) ) ]    # list is created
>>> L_above_InCACHE_computing.count( 0 )                    # list has no 0 in
0
>>> L_above_InCACHE_computing.count( range( int( 1E24 ) )  )# list has this in
1

生成器的对象内在.__len__()吐出长度,仍然没有发生计数,是吗?(很高兴它没有,它甚至不适合~ 10^20 [TB]RAM ...,但它可以作为对象“存在”在 py3+ 中)

>>> print( L[0].__doc__ )
range(stop) -> range object
range(start, stop[, step]) -> range object

Return an object that produces a sequence of integers from start (inclusive)
to stop (exclusive) by step.  range(i, j) produces i, i+1, i+2, ..., j-1.
start defaults to 0, and stop is omitted!  range(4) produces 0, 1, 2, 3.
These are exactly the valid indices for a list of 4 elements.
When step is given, it specifies the increment (or decrement).

定量公平测试?需要更好的测试工程细节:

远远超过几十 MB,以避免来自 InCACHE 计算工件的错误期望,它永远不会扩展到现实世界的问题大小:

>>> L_above_InCACHE_computing = [ range( int( 1E24 ) ) ]
>>> L_above_InCACHE_computing[0]
range(0, 999999999999999983222784)

>>> print( L_above_InCACHE_computing[0].__len__() )
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OverflowError: Python int too large to convert to C ssize_t

进入 RAM 可行,但高于 InCACHE 水平尺寸:

# L_aRunABLE_above_InCACHE_computing = [ range( int( 1E9 ) ) ] # ~8+GB ->array
# would have no sense to test 
# a benchmark on an array.array().count( something ) within an InCACHE horizon

直接进入numpy数组?

绝对是测试的明智之举。向量化的内部性可能会令人惊讶,并且经常会做很多事情:o)

很大程度上取决于您的其他代码,如果 numpy-strengths 甚至可以提升您代码库的其他部分。最后但并非最不重要的一点是,谨防过早的优化和扩展。[TIME]如果可以在 -domain 上花费更多,则可以应对一些-domain 陷阱[SPACE],但最危险的是丢失 InCACHE-locality,在这种情况下没有任何折衷可能会有所帮助。因此,最好不要过早锁定有希望的细节,以失去全球范围的性能目标为代价。

于 2018-05-12T13:07:29.707 回答