优化Python中的for循环

4 投票
9 回答
4302 浏览
提问于 2025-04-16 22:17

我有一个循环,它在某个功能中占用了我最多的时间,我想加快它的速度。目前,这个单独的循环大约需要400毫秒,而整个函数的执行时间大约是610毫秒。

代码如下:

for ctr in xrange(N):
    list1[ctr] = in1[ctr] - in1[0] - ctr * c1
    list2[ctr] = in2[ctr] - in2[0] - ctr * c2
    list3[ctr] = c3 - in1[ctr]
    list4[ctr] = c4 - in2[ctr]

N的值大约在40,000到120,000之间,代表所有列表(in1、in2、listN)的长度。

有没有人知道一些可以加速这个过程的Python技巧?我已经尝试过使用map,因为我知道它会尝试编译成更高效的代码,但结果反而慢了大约250毫秒。

谢谢!

相关问题:

9 个回答

1

优化的效果取决于编译器,但你可以尝试一些方法。很高兴看到你在对代码进行性能分析!

你可以试试:

  1. 先把 in1[ctr] 和其他经常用到的表达式存储到一个变量里(虽然大多数编译器已经能做到这一点,但谁知道呢)。

  2. 进行循环分裂(可以参考这个链接:http://en.wikipedia.org/wiki/Loop_fission),如果你在处理大数组时遇到缓存问题的话。

2

最开始的时候我犯了个小错误(见下文),这些东西其实应该更好地进行缓存。

# These can be cached as they do not change.
base_in1 = in1[0]
base_in2 = in2[0]
for ctr in xrange(N):
    # these are being looked up several times. Look-ups take time in almost every
    # language. Look them up once and then use the new value.
    cin1 = in1[ctr]
    cin2 = in2[ctr]
    list1[ctr] = cin1 - base_in1 - ctr * c1
    list2[ctr] = cin2 - base_in2 - ctr * c2
    list3[ctr] = c3 - cin1
    list4[ctr] = c4 - cin2

(下面是错误的地方):

我最开始以为可以通过缓存常量来解决这个问题:

# these values never change
ctr1 = ctr * c1
ctr2 = ctr * c2
in10 = ctr1 + in1[0]
in20 = ctr2 + in2[0]
for ctr in xrange(N):
    # these are being looked up several times. That costs time.
    # look them up once and then use the new value.
    cin1 = in1[ctr]
    cin2 = in2[ctr]
    list1[ctr] = cin1 - in10
    list2[ctr] = cin2 - in20
    list3[ctr] = c3 - cin1
    list4[ctr] = c4 - cin2

但正如Tim指出的,我在最初的尝试中漏掉了ctr

9

假设你的 list1list2 等都是数字类型的,建议使用 numpy 数组来代替普通的列表。对于大量的整数或浮点数,你会发现速度提升非常明显。

如果你选择这个方法,你上面的循环可以这样写:

ctr = np.arange(N)
list1 = n1 - n1[0] - ctr * c1
list2 = n2 - n2[0] - ctr * c2
list3 = c3 - ctr
list4 = c4 - ctr

另外,这里有一个完整的独立示例,用来测试时间:

import numpy as np
N = 100000

# Generate some random data...
n1 = np.random.random(N)
n2 = np.random.random(N)
c1, c2, c3, c4 = np.random.random(4)

ctr = np.arange(N)
list1 = n1 - n1[0] - ctr * c1
list2 = n2 - n2[0] - ctr * c2
list3 = c3 - ctr
list4 = c4 - ctr

当然,如果你的 list1list2 等不是数字(也就是说,它们是其他类型的 Python 对象,而不是浮点数或整数),那么这个方法就没什么帮助了。

撰写回答