我有一个python程序,它从文件中读取行并将它们放入dict中,简单地说,它看起来像:
data = {'file_name':''}
with open('file_name') as in_fd:
for line in in_fd:
data['file_name'] += line
我发现花了几个小时才完成。在
然后,我对程序做了一些改动:
^{pr2}$几秒钟就完成了。在
我以为这是+=
使程序变慢,但似乎不是。请查看以下测试的结果。
我知道我们可以使用list append和join来提高concat字符串的性能。但我从来没有想过在append and join和add and assign之间会有如此大的性能差距。在
所以我决定再做一些测试,最后发现是dict update操作使程序异常缓慢。以下是脚本:
import time
LOOPS = 10000
WORD = 'ABC'*100
s1=time.time()
buf1 = []
for i in xrange(LOOPS):
buf1.append(WORD)
ss = ''.join(buf1)
s2=time.time()
buf2 = ''
for i in xrange(LOOPS):
buf2 += WORD
s3=time.time()
buf3 = {'1':''}
for i in xrange(LOOPS):
buf3['1'] += WORD
s4=time.time()
buf4 = {'1':[]}
for i in xrange(LOOPS):
buf4['1'].append(WORD)
buf4['1'] = ''.join(buf4['1'])
s5=time.time()
print s2-s1, s3-s2, s4-s3, s5-s4
在我的笔记本电脑(mac pro 2013 mid、OS X 10.9.5、cpython 2.7.10)中,它的输出是:
0.00299620628357 0.00415587425232 3.49465799332 0.00231599807739
灵感来自胡安帕.阿里维拉加的评论,我对第二个循环做了一些修改:
trivial_reference = []
buf2 = ''
for i in xrange(LOOPS):
buf2 += WORD
trivial_reference.append(buf2) # add a trivial reference to avoid optimization
更改之后,现在第二个循环需要19秒才能完成。所以这似乎只是一个优化问题胡安帕.阿里维拉加说。在
+=
在构建大型字符串时执行得非常糟糕,但在CPython中有一种情况下是有效的。下面提到了为了更快地连接字符串,请使用
str.join()
。在来自Python Performance Tips下的String Concatenation部分:
避免这种情况:
请改用
s = "".join(list)
。前者是一个非常普遍和灾难性的错误时,建立大型字符串。在为什么}快?
s += x
比s['1'] += x
或{From Note 6:
对于CPython的优化是,如果一个字符串只有一个引用,那么我们可以resize it in-place。在
现在后两个不是简单的就地添加。事实上,这些都是不到位的补充。在
s[0] += x
相当于:
^{pr2}$示例:
但通常不要使用
s += x
来连接字符串,而应该在字符串集合上使用str.join
。在计时
val_pop_concat
在这里很快,因为通过使用pop()
我们将从列表中删除对该字符串的引用,现在CPython可以适当地调整它的大小(由@niemmi in comments正确猜测)。在相关问题 更多 >
编程相关推荐