[英]Python string concatenation loop
%timeit为这两个实现提供的结果让我感到惊讶:
def f1():
s = ''
for i in range(len(values)):
s += str(values[i][0])
s += '\t'
s += str(values[i][1])
s += '\r\n'
return s
和
def f2():
return ''.join((
str(ts) + '\t' + str(v) + '\r\n'
for ts, v in values
))
知道values
是大约2400个元组的列表。 f1()
是我在一个由同事编写的脚本中找到的原始代码,该脚本更熟悉C / C ++,而在他写Python时对Python更为熟悉,而f2
是恕我直言,我将为相同的处理编写的Pythonic风格越多。
我本来希望f2
比f1
快得多,这主要是因为f1
使用了许多串联和字符串重新分配,但是%timeit
给出了两者的大小顺序相同(大约18ns),更令人惊讶的是,给f2
1ns更快,有时1ns。
这样的结果可能是什么解释?
[7月14日编辑]修复了f1,以用具有相同名称的局部变量覆盖str
。 但是,概要文件代码中不存在此错误。
由于以下原因,f2代码仍然受字符串连接的约束
str(ts) + '\\t' + str(v) + '\\r\\n'
它比基于字符串concat的原始版本要差的事实,可能是由于另一个问题中提到的实现细节。
如果将内部串联更改为也使用连接,则将获得更好的性能。
def f2(values):
return '\r\n'.join(
('\t'.join([str(ts), str(v)])
for ts, v in values))
我可以肯定地说,您的测试方法无效,正如Py2.7的repl.it和Py3的 repl.it所证明的那样 。 相同的代码,如下所示,但结果有所不同:
f1是您的f1函数
f2是您的f2函数
f3是使用c样式字符串格式"%s" % str
f2函数
f4是使用.format()
f2函数
结果:
Python 2.7.10 (default, Jul 14 2015, 19:46:27)
[GCC 4.8.2] on linux
1.67547893524
1.33767485619
0.72606086731
1.32540607452
有一些区别,但是在任何情况下f1都不会超过以下任何一种方法。
Python 3.6.1 (default, Dec 2015, 13:05:11)
[GCC 4.8.2] on linux
3.0050943629757967
2.016791722999187
0.9476796620001551
1.9396837950043846
在这两种情况下,c样式字符串格式化的速度都快两倍以上。
使用的功能:
def f1():
s = ''
for i in range(len(values)):
s += str(values[i][0])
s += '\t'
s += str(values[i][1])
s += '\r\n'
return s
def f2():
return ''.join((
str(ts) + '\t' + str(v) + '\r\n'
for ts, v in values))
def f3():
return ''.join((
"%s\t%s\r\n" % (ts, v)
for ts, v in values))
def f4():
return ''.join((
"{}\t{}\r\n".format(ts, v)
for ts, v in values))
有趣的是,通过对f1函数进行少量更改,我们可以利用 danny引用的字节码加速来达到不错的速度:
def f1opt():
s = ''
for i in range(len(values)):
s += str(values[i][0]) + '\t' + str(values[i][1]) + '\r\n'
return s
产量
Python 2.7.10 (default, Jul 14 2015, 19:46:27)
[GCC 4.8.2] on linux
f1() 1.68486714363
f1bytecode() 0.999644994736
由于观察到的结果令我有些惊讶,因此我使用以下脚本进行了相同的分析:
import random
import timeit
data = [(random.randint(0, 100000), random.randint(0, 1000)) for _ in range(0, 2500)]
def f1():
return ''.join(('{}\t{}\r\n'.format(ts, v) for ts, v in data))
def f2():
s = ''
for i in range(len(data)):
s += str(data[i][0])
s += '\t'
s += str(data[i][1])
s += '\r\n'
return s
if __name__ == '__main__':
repeat = 10000
for f in ['f1', 'f2']:
t = timeit.timeit(
'%s()' % f, number=repeat, setup="from __main__ import %s" % f
)
print(
"%s : avg time per loop = %f ms" % (f, t * 1000 / repeat)
)
现在的输出是:
f1 : avg time per loop = 0.779966 ms
f2 : avg time per loop = 1.144340 ms
这更符合预期的结果。
我将进行更多调查,以了解两种测试在行为上的差异。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.