Python字节数组与字节列表

Python字节数组与字节列表,python,list,bytearray,Python,List,Bytearray,我试图找出创建长字节字符串(或bytearray)的最有效方法,即在预先知道整个字符串的长度的情况下,通过连接多个较短的字符串。我制作了这个脚本并得出了以下结果: import time MSG = b'test message' COUNT = 30000 def bytes_list_test(): tStart = time.clock() l = [] for i in range(COUNT): l.append(MSG) bs

我试图找出创建长字节字符串(或bytearray)的最有效方法,即在预先知道整个字符串的长度的情况下,通过连接多个较短的字符串。我制作了这个脚本并得出了以下结果:

import time

MSG = b'test message'
COUNT = 30000

def bytes_list_test():  
    tStart = time.clock()
    l = []
    for i in range(COUNT):
        l.append(MSG)
    bs = b''.join(l)
    print('byte list time:', time.clock() - tStart)

def bytearray_test():
    tStart = time.clock()
    ba = bytearray()
    for i in range(COUNT):
        for c in MSG:
            ba.append(c)
    print('array time:', time.clock() - tStart)

def initialized_bytearray_test():
    tStart = time.clock()
    ba = bytearray([0x00]*len(MSG)*COUNT)
    for i in range(COUNT):
        ba[i*len(MSG):i*len(MSG)+len(MSG)] = MSG
    print('initialized array time:', time.clock() - tStart)

bytes_list_test()
bytearray_test()
initialized_bytearray_test()
结果:

byte list time:         0.0076534920117410365
array time:             0.08107178658246994
initialized array time: 0.08843219671325642
有几个问题:

1) 创建字节列表并使用join()方法是否与结果所暗示的方式相同

2) 为什么使用字节列表要比使用bytearray快得多,因为bytearray似乎是为这种类型的东西设计的


3) 您可能会认为初始化的数组比未初始化的数组快,因为初始化的数组不需要调整大小(注意,它偶尔会表现得更好,但不会有太多不一致的地方)。它不是因为切片操作而更快吗?

第一个函数创建指向同一对象的指针列表(不是字节列表),然后
join
将执行一次内存分配和
COUNT
调用
memcpy

通过删除临时列表并使用
itertools,您可以将第一个函数的速度提高5倍(在我的测试中是5倍)。重复

def bytes_list_test_opt():  
    tStart = time.clock()
    bs = b''.join(itertools.repeat(MSG, COUNT))
    print('byte list opt time:', time.clock() - tStart)
或者,在这种特殊情况下,只需使用
*
字节的
操作符
对象,它就可以做到:

    bs = MSG*COUNT
第二个函数反复迭代
MSG
,逐字节存储数据,并且随着字节数组的增长,必须反复重新分配内存

通过将迭代替换为对
extend
的单个调用,可以使第二个函数几乎与原始(未优化)的第一个函数一样快:

def bytearray_test_opt():
    tStart = time.clock()
    ba = bytearray()
    for i in range(COUNT):
        ba.extend(MSG)
    print('array opt time:', time.clock() - tStart)
在这个修改之后,第二个函数将比第一个函数慢,这仅仅是因为额外的重新分配(在我的测试中约为15%)

第三个函数使用
bytearray
的片分配,它接受iterable,似乎在进行相同的逐字节迭代,而没有意识到它们可以将
memcpy
字节放入该位置。这看起来像是标准库中可以修复的缺陷

正如您从前面的优化中看到的,与逐字节复制相比,分配占用的时间非常少,因此预分配在这里没有明显的影响。你可以节省一些时间来做更少的计算,但这也不会有多大帮助:

def initialized_bytearray_test_opt():
    tStart = time.clock()
    L = len(MSG)
    ba = bytearray(L*COUNT)
    ofs = 0
    for i in range(COUNT):
        ba[ofs : ofs+L] = MSG
        ofs += L
    print('initialized array opt time:', time.clock() - tStart)
我的机器的最终计时:

byte list time: 0.004823000000000001
byte list opt time: 0.0008649999999999977
array time: 0.043324
array opt time: 0.005505999999999997
initialized array time: 0.05936899999999999
initialized array opt time: 0.040164000000000005
另外,使用
timeit
模块执行此类测量,它提供了更高的精度