我在C ++中有一个继承自std::vector<char>
的缓冲区对象。我想将此缓冲区转换为Python字符串,以便我可以通过Twisted的protocol.transport.write将其发送出去。
我想到的两种方法是(1)创建一个字符串并用char填充它:
def scpychar(buf, n):
s = ''
for i in xrange(0, n):
s += buf[i]
return s
和(2)制作一个char数组(因为我知道缓冲区有多大),填充它并将其转换为字符串
def scpyarr(buf, n):
a = array.array('c','0'*n)
for i in xrange(0, n):
a[i] = buf[i]
return a.tostring()
我原以为(1)每次调用s += buf[i]
时都必须创建一个新的字符串对象,并复制旧字符串的内容。所以我期待(2)比(1)更快。但是,如果我使用timeit测试它,我发现(1)实际上大约是(2)的两倍。
我想知道是否有人可以解释为什么(1)更快?
奖励积分可以更有效地将std::vector<char>
转换为Python字符串。
答案 0 :(得分:2)
CPython有时可以优化字符串+=
,如果它可以确定没有人保留对旧字符串的引用。算法(1)可能触发了优化,因此它不会受到其他情况下的二次运行时间的影响。但是,这种行为无法保证,其他Python实现可能不支持它。
尝试
''.join(buf)
它应该在任何Python实现上提供线性时间性能,不像(1),并且比(2)更快。
答案 1 :(得分:-1)
导入dis并查看dis.dis(scpyarr)和dis.dis(scpychar)。 scpychar具有较少的解释器操作。
>>> import dis
>>> def scpyarr(buf, n):
... a = array.array('c','0'*n)
... for i in xrange(0, n):
... a[i] = buf[i]
... return a.tostring()
...
>>> dis.dis(scpyarr)
2 0 LOAD_GLOBAL 0 (array)
3 LOAD_ATTR 0 (array)
6 LOAD_CONST 1 ('c')
9 LOAD_CONST 2 ('0')
12 LOAD_FAST 1 (n)
15 BINARY_MULTIPLY
16 CALL_FUNCTION 2
19 STORE_FAST 2 (a)
3 22 SETUP_LOOP 37 (to 62)
25 LOAD_GLOBAL 1 (xrange)
28 LOAD_CONST 3 (0)
31 LOAD_FAST 1 (n)
34 CALL_FUNCTION 2
37 GET_ITER
>> 38 FOR_ITER 20 (to 61)
41 STORE_FAST 3 (i)
4 44 LOAD_FAST 0 (buf)
47 LOAD_FAST 3 (i)
50 BINARY_SUBSCR
51 LOAD_FAST 2 (a)
54 LOAD_FAST 3 (i)
57 STORE_SUBSCR
58 JUMP_ABSOLUTE 38
>> 61 POP_BLOCK
5 >> 62 LOAD_FAST 2 (a)
65 LOAD_ATTR 2 (tostring)
68 CALL_FUNCTION 0
71 RETURN_VALUE
>>> def scpychar(buf, n):
... s = ''
... for i in xrange(0, n):
... s += buf[i]
... return s
...
>>> dis.dis(scpychar)
2 0 LOAD_CONST 1 ('')
3 STORE_FAST 2 (s)
3 6 SETUP_LOOP 37 (to 46)
9 LOAD_GLOBAL 0 (xrange)
12 LOAD_CONST 2 (0)
15 LOAD_FAST 1 (n)
18 CALL_FUNCTION 2
21 GET_ITER
>> 22 FOR_ITER 20 (to 45)
25 STORE_FAST 3 (i)
4 28 LOAD_FAST 2 (s)
31 LOAD_FAST 0 (buf)
34 LOAD_FAST 3 (i)
37 BINARY_SUBSCR
38 INPLACE_ADD
39 STORE_FAST 2 (s)
42 JUMP_ABSOLUTE 22
>> 45 POP_BLOCK
5 >> 46 LOAD_FAST 2 (s)
49 RETURN_VALUE
>>>
比较它:
51 LOAD_FAST 2 (a)
54 LOAD_FAST 3 (i)
57 STORE_SUBSCR
加
>> 62 LOAD_FAST 2 (a)
65 LOAD_ATTR 2 (tostring)
68 CALL_FUNCTION 0
VS
38 INPLACE_ADD
39 STORE_FAST
负载很慢。 CALL_FUNCTION很慢。
我在一个月前看到问题,''.join(b)
是将字符数组连接成一个字符串的最快方法。