Python 字节数组与字节列表

标签 python list arrays

当事先知道整个字符串的长度时,我试图通过连接多个较短的字符串来找到创建长字节字符串(或字节数组)的最有效方法。我制作了这个脚本并得出了这些结果:

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)为什么使用字节列表比使用字节数组快得多,字节数组似乎是为此类事情设计的?

3) 您可能会认为初始化的数组会比未初始化的数组更快,因为初始化的数组不必调整大小(请注意,它偶尔会表现得更好,但幅度不会很大,而且不一致)。因为切片操作不是更快吗?

最佳答案

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

通过删除临时列表并使用 itertools.repeat ,您可以使第一个函数速度更快(在我的测试中为 5 倍)。 :

def bytes_list_test_opt():  
    tStart = time.clock()
    bs = b''.join(itertools.repeat(MSG, COUNT))
    print('byte list opt time:', time.clock() - tStart)

或者,在这种特殊情况下,只需使用 * bytes 的运算符对象,它正是这样做的:

    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的切片分配,它接受可迭代,并且似乎正在执行相同的逐字节迭代,但没有意识到它们可以只是 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模块来执行这样的测量,它提供了更高的准确性。

关于Python 字节数组与字节列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17162609/

相关文章:

c++ - 检查字符数组 - 每次都返回相同的答案

python - AWS Elasticbeanstalk : Command 02_createadmin failed 上的 Django

python - "setup.py clean"究竟是做什么的?

python - 如何对整数列表的一部分进行排序?

python - 打印链接到列表中键的字典值

javascript - 选择不是第一个 child 且不包含某些内容的所有 `li`

python - Pandas :来自数据框的订单值

Python 请求 header 。如何解析这个? ast 的语法无效?

python - Python 中的 Adwords 数组,没有属性 'get'

c - 为数组分配一个随机值