python - Pypy vs Python 中的计数算法性能优化(Numpy vs List)

标签 python performance optimization numpy pypy

我的期望是 pypy 可能比 python 快一个数量级,但结果表明 pypy 实际上比预期的要慢。

我有两个问题:

  1. 为什么使用 numpy 时 pypy 明显变慢?
  2. 我可以做些什么来优化我的算法以使 pypy(或 python)更快?

结果计时:

python 2.7.5

  • # 分:16,777,216 (8 ** 3 * 32 ** 3)
  • Xrange 时间:1487.15 毫秒
  • Xrange Numpy 时间:2553.98 毫秒
  • 点生成时间:6162.23 毫秒
  • Numpy 生成时间:13894.73 毫秒

派皮 2.2.1

  • # 分:16,777,216 (8 ** 3 * 32 ** 3)
  • Xrange 时间:129.48 毫秒
  • Xrange Numpy 时间:4644.12 毫秒
  • 点生成时间:4643.82 毫秒
  • Numpy 生成时间:44168.98 毫秒

算法:

我正在使用一种简单的算法生成空间中的点列表,并且正在尝试优化该算法。

def generate(size=32, point=(0, 0, 0), width=32):
    """
    generate points in space around a center point with a specific width and
      number of divisions (size)
    """
    X, Y, Z = point
    half = width * 0.5
    delta = width
    scale = width / size
    offset = scale * 0.5
    X = X + offset - half
    Y = Y + offset - half
    Z = Z + offset - half
    for x in xrange(size):
        x = (x * scale) + X
        for y in xrange(size):
            y = (y * scale) + Y
            for z in xrange(size):
                z = (z * scale) + Z
                yield (x, y, z)

在优化方面,我开始考虑使用 pypy 而不是 python。在比较两者时,我想到了几个不同的场景:

  • 使用 xrange 计数

    rsize = 8    # size of region
    csize = 32   # size of chunk
    number_of_points = rsize ** 3 * csize ** 3
    [x for x in xrange(number_of_points)]
    
  • 使用 xrange 和 numpy 进行计数

    rsize = 8    # size of region
    csize = 32   # size of chunk
    number_of_points = rsize ** 3 * csize ** 3
    np.array([x for x in xrange(number_of_points)])
    
  • 运行上面的算法

    rsize = 8    # size of region
    csize = 32   # size of chunk
    [p
     for rp in generate(size=rsize, width=rsize*csize)
     for p in generate(size=csize, width=csize, point=rp)]
    
  • 用 numpy 运行上面的算法

    rsize = 8    # size of region
    csize = 32   # size of chunk
    np.array([p
     for rp in generate(size=rsize, width=rsize*csize)
     for p in generate(size=csize, width=csize, point=rp)])
    

背景:

我正在尝试创建一个体素引擎,我想优化我的算法以将生成时间降低到可管理的水平。虽然我显然不会实现任何接近 Java/C++ 的东西,但我想尽可能地插入 python(或 pypy)。

我注意到列表查找比早期的字典查找要快得多。列表也比元组快(出乎意料),尽管元组生成速度更快。 Numpy 的读取时间甚至比非 numpy 更快。但是,numpy 创建时间可能会慢几个数量级。

因此,如果阅读是最重要的,那么使用 numpy 有明显的优势。然而,如果阅读和创作同等重要,那么直接列出可能是最好的。也就是说,我没有一个干净的方法来查看内存使用情况,但我怀疑列表的内存效率远低于元组或 numpy。 此外,虽然差异很小,但我发现字典上的 .get 比使用 __ getitem __ 调用稍快(即 dictionary[lookup] 与 dicitonary.get(lookup) )

时间...

python 2.7.5

读书

 - Option 1: tuple access... 2045.51 ms
 - Option 2: tuple access (again)... 2081.97 ms    # sampling effect of cache
 - Option 3: list access... 2072.09 ms
 - Option 4: dict access... 3436.53 ms
 - Option 5: iterable creation... N/A
 - Option 6: numpy array... 1752.44 ms

创作

 - Option 1: tuple creation... 690.36 ms
 - Option 2: tuple creation (again)... 716.49 ms    # sampling effect of cache
 - Option 3: list creation... 684.28 ms
 - Option 4: dict creation... 1498.94 ms
 - Option 5: iterable creation...  0.01 ms
 - Option 6: numpy creation... 3514.25 ms

派皮 2.2.1

读书

 - Option 1: tuple access... 243.34 ms
 - Option 2: tuple access (again)... 246.51 ms    # sampling effect of cache
 - Option 3: list access... 139.65 ms
 - Option 4: dict access... 454.65 ms
 - Option 5: iterable creation... N/A
 - Option 6: numpy array... 21.60 ms

创作

 - Option 1: tuple creation... 1016.27 ms
 - Option 2: tuple creation (again)... 1063.50 ms    # sampling effect of cache
 - Option 3: list creation... 365.98 ms
 - Option 4: dict creation... 2258.44 ms
 - Option 5: iterable creation...  0.00 ms
 - Option 6: numpy creation... 12514.20 ms

在所有示例中,随机查找都是针对随机数据生成的。

dsize = 10 ** 7   # or 10 million data points
data = [(i, random.random()*dsize)
         for i in range(dsize)]
lookup = tuple(int(random.random()*dsize) for i in range(dsize))

循环非常简单:

for x in lookup:
    data_of_specific_type[x]

data_of_specific_type 是将数据转换为该类型(例如元组(数据)、列表(数据)等)

最佳答案

部分问题在于:

np.array([p
    for rp in generate(size=rsize, width=rsize*csize)
    for p in generate(size=csize, width=csize, point=rp)])

创建列表并将其转换为np.array的所有工作。

更快的方法是:

arr = np.empty(size)
i = 0
for rp in generate(size=rsize, width=rsize*csize):
    for p in generate(size=csize, width=csize, point=rp):
        arr[i] = p
        i += 1

关于python - Pypy vs Python 中的计数算法性能优化(Numpy vs List),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23818691/

相关文章:

Python Metaclass 使用时没有改变类

python - 在 numpy 中计算高于阈值的数组值的最快方法

python - 理解Python的导入__main__

python - NumPy ndarray.all() vs np.all(ndarray) vs all(ndarray)

java - 消息队列性能低下

multithreading - 使用 OpenMP 的无用 printf 无法加速

algorithm - Firebug 算法: How to understand the movement formula

javascript - 哪种方法更快?条件 IF 还是数学公式?

c++ - 关于点到线的非线性优化

python - Python 中应用于类的方法的表示