【问题标题】:How can I speed up array generations in python?如何在 python 中加速数组生成?
【发布时间】:2011-03-11 17:27:05
【问题描述】:

我想我需要使用 numpy 或其他一些库来足够快地填充这些数组,但我对此知之甚少。现在这个操作在四核英特尔 PC 上大约需要 1 秒,但我需要它尽可能快。任何帮助是极大的赞赏。谢谢!

import cv

class TestClass:

  def __init__(self):

    w = 960
    h = 540

    self.offx = cv.CreateMat(h, w, cv.CV_32FC1)
    self.offy = cv.CreateMat(h, w, cv.CV_32FC1)

    for y in range(h):
      for x in range(w):
        self.offx[y,x] = x
        self.offy[y,x] = y

【问题讨论】:

    标签: python arrays matrix performance opencv


    【解决方案1】:

    我八岁的(慢速)计算机能够在 127 毫秒内创建一个与您的矩阵大小相同的列表。

    C:\Documents and Settings\gdk\Desktop>python -m timeit "[[x for x in range(960)]
     for y in range(540)]"
    10 loops, best of 3: 127 msec per loop
    

    我不知道 cv 模块是什么以及它如何创建矩阵。但也许这就是代码慢的原因。

    Numpy 可能更快。创建一个 (python int) 1s 的数组:

    C:\Documents and Settings\gdk\Desktop>python -m timeit -s "from numpy import one
    s" "ones((960, 540), int)"
    100 loops, best of 3: 6.54 msec per loop
    

    您可以比较使用不同模块创建矩阵的时间,看看更改是否有好处:timeit module

    【讨论】:

    • 尽管您的答案解决了时间问题,但它并没有完全按照原始问题中的代码所做的那样。因此,您的比较是偏见。此外,您发布的两个代码做不同的事情,所以比较是不公平的。
    • 当然我的代码和问题的不一样。我也没有说 OP 应该使用我的代码。我提供的示例是展示如何为创建大型矩阵类对象的不同方法计时。我的最后一句话告诉 OP 为不同的方法计时,以便他可以决定改变是否有好处 - 在他有证据表明另一种方法更快或更有效之前,他不应该做出改变。
    【解决方案2】:

    您正在生成 50 万个整数并创建超过 100 万个引用。我很高兴它只需要 1 秒。

    如果你经常这样做,你应该考虑缓存结果的方法。

    此外,在这种情况下,在四核上任何东西都无济于事,您正在执行一次只能在一个核心上执行的串行操作(即使您对它进行线程化,CPython 也只能由于全局解释器锁,一次执行一个纯 Python 线程)。

    【讨论】:

    • 为什么这被标记为解决方案?它根本没有回答这个问题,而且充其量也是一种误导——在 Python 中(在典型的 PC 上)创建一百万个整数和一百万个引用并不需要任何时间。
    【解决方案3】:

    Numpy 中的代码与您在 OpenCV python 中所做的完全一样

    import numpy as np
    offsetx, offsety = np.meshgrid(range(960),range(540))
    

    如果您使用 Python,考虑学习 numpy 的不同功能将对您有很大帮助。 OpenCV 函数也可以直接使用 numpy 数组。 Python中numpy的语法虽然比OpenCV好很多。

    这是我的 i7 中两个版本的时间

    time python test.py
    
    real    0m0.654s 
    user    0m0.640s
    sys 0m0.010s
    

    我的版本:

    time python test2.py
    
    real    0m0.075s
    user    0m0.060s
    sys 0m0.020s
    

    【讨论】:

      【解决方案4】:

      如果您一遍又一遍地创建相同的矩阵,使用cv.SetData() 初始化它可能会更快

      【讨论】:

        【解决方案5】:

        好吧,您至少可以使用 xrange 代替 range。 range 创建所有这些数字的完整列表。 xrange 逐个生成它们。由于您一次只使用一个,因此不需要它们的列表。

        【讨论】:

        • 我认为,现代 Python 解释器会自动将“for range(...)”更改为“for xrange(...)”。所以它只是理论上的优化或一些简单(不太聪明)的解释器。
        • 在 Python 2.x(包括刚刚发布的 2.7)中,内置的 range 仍然返回一个列表,因此使用 xrange 是一种优化。在 Python 3 中,range 返回一个 range 对象,这是一个类似于 Python 2 中 xrange 返回的可迭代对象。
        • 我在 Python 2.6.1 中的计时显示 range 采用 4.70 秒,xrange 采用 2.29。我使用的代码是 for i in range(1000000): pass 和 xrange 相同。使用 number=100 的 timeit。
        【解决方案6】:

        我没有完全理解你想要达到的目标。但这里有两个具体的例子和基准可以帮助你。他们都做同样的事情,用红色填充 960x540 图像(数组)。

        slow.py 使用 for 循环填充数组

        import cv2
        import numpy as np
        
        width, height = 960, 540
        image = np.zeros((height, width, 3), np.uint8)
        # Fill array with red
        for y in range(height):
            for x in range(width):
                image[y, x] = (0, 0, 255)
        
        cv2.imwrite('red.jpg', image)
        

        运行时间

        $ time python slow.py
        real    0m2.240s
        user    0m2.172s
        sys 0m0.040s
        

        fast.py 使用 numpy 填充数组

        import cv2
        import numpy as np
        
        width, height = 960, 540    
        image = np.zeros((height, width, 3), np.uint8)
        # Fill array with red
        image[:] = (0, 0, 255)
        cv2.imwrite('red.jpg', image)
        

        运行时间

        $ time python fast.py
        real    0m0.134s
        user    0m0.084s
        sys 0m0.024s
        

        使用 numpy 代替 for 循环几乎快 17 倍

        【讨论】:

          猜你喜欢
          • 2018-11-19
          • 1970-01-01
          • 2015-03-20
          • 2022-06-13
          • 1970-01-01
          • 2011-01-08
          • 2020-12-04
          • 2023-04-07
          • 1970-01-01
          相关资源
          最近更新 更多