【问题标题】:Accelerating for loops with list methods in Python在 Python 中使用列表方法加速 for 循环
【发布时间】:2015-10-14 12:14:06
【问题描述】:

我在 python 中有 for 循环,它迭代了近 250 万次,而且需要很长时间才能得到结果。在 JS 中,我可以在将近 1 秒内完成此操作,但 Python 在我的计算机上只需 6 秒即可完成。在这种情况下,我必须使用 Python。代码如下:

            for i in xrange(k,p,2):
                arx = process[i]
                ary = process[i+1]
                for j in xrange(7,-1,-1):
                    nx = arx + dirf[j]
                    ny = ary + dirg[j]
                    ind = ny*w+nx
                    if data[ind] == e[j]:       
                        process[c]=nx
                        c=c+1
                        process[c]=ny
                        c=c+1
                        matrix[ind]=1

以下是代码中的一些列表: process = [None] * (11000*4)它的项目在赋值后将被替换为整数。

dirf = [-1,0,1,-1,1,-1,0,1]
dirg = [1,1,1,0,0,-1,-1,-1]
e = [9, 8, 7, 6, 4, 3, 2, 1] 

数据列表由来自 rgba 图像像素的“r”个信息组成。 data = imgobj.getdata(0)

我怎样才能提高这一点。我究竟做错了什么?还有其他关于 for 循环的方法吗?谢谢。

【问题讨论】:

  • 在我的机器上迭代 250 万次需要 34.9 毫秒(虽然很慢,但并不慢 6 秒)。
  • 如果你必须和他们一起工作;你应该问他们:他们做什么?目的是什么?这是一个很好的入门参考:How to optimize for speed
  • numba、numeric python (numpy.org) 或 cython (cython.org) 等库将为您提供一些提高性能的选项
  • 您的计时方式可能会使事情发生偏差 - 在之前和之后取 time.time() 并减去是不是最佳做法;相反,请使用timeit 模块对整个脚本进行计时,并使用profiling 获取有关减慢它的详细信息。我不能完全理解你的 pastebin'd 代码在做什么,但看起来 numpy 确实是一个不错的选择——无论是速度还是可读性。
  • 另外,请考虑在codereview.SE 上询问有关性能问题和其他工作代码中的一般最佳实践的问题。

标签: python list for-loop iteration


【解决方案1】:

以下是一些改进代码的建议:

内部 xrange 被大量使用:如果您将其设为常规列表并执行以下操作会怎样:

inner = range(7,-1,-1) # make the actual list
for(a,b,c): #first for
    #stuff
    for i in inner # reference an actual list and not the generator

证据:

n = range(7,-1,-1)
def one():
    z = 0
    for k in xrange(100):
        for i in n:
            z+=1

def two():
    z = 0
    for k in xrange(100):
        for i in xrange(7,-1,-1):
            z+=1

if __name__ == '__main__':
    import timeit
    print("one:")
    print(timeit.timeit("one()",number=1000000 ,setup="from __main__ import one"))
    print("two:")
    print(timeit.timeit("two()",number=1000000 ,setup="from __main__ import two"))

"result" 
one:
37.798637867
two:
63.5098838806

如果我编写的代码具有可比性,则似乎表明引用内部列表而不生成确实会加快速度。 [编辑] 引用局部变量比访问全局变量要快。 因此,如果这是正确的,则将列表定义尽可能靠近循环,而不是每次都生成它。

您还更改了两次流程。如果不需要,只需选择一个即可。

正如您在 cmets 中提到的,您说您正在处理图像。我不确定以下内容是否相关,但也许您可以使用 openCV,它有一个 Python API 到 C 代码。那可能会加快速度。正如其他人所提到的:numpy 和您自己的 cython 扩展将大大加快这一速度。

【讨论】:

  • 您的分配计时集没有显示十分之一秒的加速 - 最后的 e-08 意味着差异实际上大约是 一纳秒。您每次在循环中不调用 xrange 的时间会加快 (63.5 - 37.8)/100,000 秒,即 just under 26 microseconds。即使在关键的内部循环中,这些类型的微优化对整体运行时间的影响也可能完全可以忽略不计。
  • 是的,我同意,我忘了看指数,将删除该部分
  • 不过,您留下的位几乎一样糟糕,因为 a) 您没有对通过次数的时间进行平均,并且 b) 您正在测试的更改会影响整个外循环一次。即使 OP 外部循环的迭代次数比您的示例多得多,您也提供了证据表明它们最多可以节省六秒运行时间的几毫秒。
猜你喜欢
  • 2018-12-27
  • 2021-01-30
  • 1970-01-01
  • 2017-08-16
  • 1970-01-01
  • 2020-03-23
  • 1970-01-01
  • 2020-10-22
  • 2023-04-04
相关资源
最近更新 更多