我有一个循环,这是我最大的时间吮吸一个特定的功能,我想加快它。目前,这个单循环占用大约400ms,而其余功能的执行大约需要610ms。
代码是:
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,因为我知道它会尝试编译为更高效的代码,但速度大约慢了250ms。
由于
答案 0 :(得分:9)
假设list1
,list2
等都是数字,请考虑使用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
当然,如果你的list1
,list2
等是非数字的(即浮点数或整数以外的python对象列表),那么这将无济于事。
答案 1 :(得分: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
但正如蒂姆指出的那样,我在原来的尝试中错过了ctr
。
答案 2 :(得分:1)
优化取决于编译器,但您可以尝试一些事项。很高兴看到你正在分析代码!
您可以尝试:
首先在变量中存储in1[ctr]
和其他多次使用的表达式(尽管大多数编译器已经可以执行此操作,谁知道)。
循环裂变(http://en.wikipedia.org/wiki/Loop_fission),以防您遇到缓存问题,在大规模阵列之间交替。
答案 3 :(得分:1)
从我注意到的情况来看,Python在连续的数学表达式上是不好的,并且会大大减速。你最好的选择可能会像其他人所说的那样使用numpy,因此代码在C中运行。另外一个Python优化尝试是使用列表推导。列表推导通常比地图更快。
in = in1[0]
list1 = [x - in - i * c1 for i, x in enumerate(in1)]
此方法根本不涉及使用xrange(使用Python非常强大的迭代函数)。
使用timeit的示例。
>>> import timeit
>>> timeit.timeit(stmt="[x * 2 for x in xrange(1000)]", number=10000)
8.27007...
>>> timeit.timeit(stmt="map(lambda x: x * 2, xrange(1000))", number=10000)
19.5969...
>>> timeit.timeit(stmt="""lst=[0]*1000
for x in xrange(1000):
lst[x] = x * 2
""", number=10000)
13.7785...
# this last one doesn't actually do what you want it to do, but for comparison
# it's faster because it doesn't have to store any data from the computation
>>> timeit.timeit(stmt="for x in xrange(1000): x * 2", number=10000)
6.98619...
(如果你需要帮助构建其他4个列表推导,只需评论)
编辑:一些时间示例。
答案 4 :(得分:0)
您可以尝试将其重写为多个循环:
for ctr in xrange(N):
list1[ctr] = in1[ctr] - in1[0] - ctr * c1
for ctr in xrange(N):
list2[ctr] = in2[ctr] - in2[0] - ctr * c2
for ctr in xrange(N):
list3[ctr] = c3 - in1[ctr]
for ctr in xrange(N):
list4[ctr] = c4 - in2[ctr]
它可能不像听起来那么愚蠢。测量它。这种代码的一个问题可能是引用的局部性。如果你在内存中跳跃,你可以对抗缓存。您可能会发现单独压缩数组可能在缓存上更友好。
您还可以考虑在并行线程中执行它们。
答案 5 :(得分:0)
itertools.count
速度更快。 map
在Python 2中生成一个列表,您需要itertools.imap
。
答案 6 :(得分:0)
如果您有随机访问权限,地图只会有帮助。在您的情况下,列表是正确的数据类型。
尝试从循环中提取常量。哎呀。 in1[0] - ctr * c1
和in2[0] - ctr * c2
ctr
不是常数。您可以尝试x1 = c1,然后尝试x1 + = c1,但我不认为添加速度比现在的CPU更快。
然后,您应该查看array module或Numpy。不要在代码中创建list3
,而是创建in1
的副本,反转所有元素(*-1
),然后将c3
添加到每个元素。 array / Numpy的质量变异方法将使这一过程更快。
除此之外,如果不触及剩下的代码,你几乎无能为力。例如,您可以创建在必要时返回值的对象,而不是实际计算list3
和list4
。但我的猜测是你需要所有的价值观,所以这无济于事。
如果速度不够快,则必须使用其他语言或编写C模块。
答案 7 :(得分:0)
使用numpy。循环被数组的一些差异所取代,其评估在C中完成。
答案 8 :(得分:0)
使用列表推导来计算列表内容比使用for循环要快一些。
import random
N = 40000
c1 = 4
c2 = 9
c3 = 11
c4 = 8
in1 = [random.randint(1, 50000) for _ in xrange(N)]
in2 = [random.randint(1, 50000) for _ in xrange(N)]
list1 = [None for _ in xrange(N)]
list2 = [None for _ in xrange(N)]
list3 = [None for _ in xrange(N)]
list4 = [None for _ in xrange(N)]
in1_0 = in1[0]
in2_0 = in2[0]
def func():
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]
def func2():
global list1, list2, list3, list4
list1 = [(in1[ctr] - in1_0 - ctr * c1) for ctr in xrange(N)]
list2 = [(in2[ctr] - in2_0 - ctr * c2) for ctr in xrange(N)]
list3 = [(c3 - in1[ctr]) for ctr in xrange(N)]
list4 = [(c4 - in2[ctr]) for ctr in xrange(N)]
然后是timeit结果:
% python -mtimeit -s 'import flup' 'flup.func()'
10 loops, best of 3: 42 msec per loop
% python -mtimeit -s 'import flup' 'flup.func2()'
10 loops, best of 3: 34.1 msec per loop