是否可以使用非零值有效地初始化 bytearray?

Is it possible to effectively initialize bytearray with non-zero value?

我需要一个巨大的布尔数组。所有值都应初始化为 "True":

arr = [True] * (10 ** 9)

但是按上面的方法创建太占内存了。所以我决定为此使用 bytearray

arr = bytearray(10 ** 9)  # initialized with zeroes

是否可以用 b'\x01' 初始化 bytearray 和用 b'\x00' 初始化一样有效?

我知道我可以用零初始化 bytearray 并反转我的逻辑。但如果可能的话,我宁愿不这样做。

时间:

>>> from timeit import timeit
>>> def f1():
...   return bytearray(10**9)
... 
>>> def f2():
...   return bytearray(b'\x01'*(10**9))
... 
>>> timeit(f1, number=100)
14.117428014000325
>>> timeit(f2, number=100)
51.42543800899875

您在使用 numpy 吗?你可以这样做:

import numpy as np
np.ones(10,dtype=bool)

Returns:

array([ True,  True,  True,  True,  True,  True,  True,  True,  True,  True], dtype=bool)

此外,您可以使用 ndarray.tobytes() 轻松转换回字节,如:

x = np.ones(10,dtype=bool)
x.tobytes()
# returns: b'\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01'

有关详细信息,请参阅

考虑使用 NumPy 来处理这类事情。在我的电脑上,使用布尔值 "dtype" 的 np.ones(初始化全 1 值的数组)与裸 bytearray 构造函数一样快:

>>> import numpy as np
>>> from timeit import timeit
>>> def f1(): return bytearray(10**9)
>>> def f2(): return np.ones(10**9, dtype=np.bool)
>>> timeit(f1, number=100)
24.9679438900057
>>> timeit(f2, number=100)
24.732190757000353

如果您不想使用第三方模块,另一个具有竞争力的选择是创建一个单元素 bytearray 然后扩展它,而不是创建一个大字节串并转换它到字节数组。

>>> def f3(): return bytearray(b'\x01')*(10**9)
>>> timeit(f3, number=100)
24.842667759003234

由于我的电脑似乎比你的慢,这里是你的原始选项的性能比较:

>>> def fX(): return bytearray(b'\x01'*(10**9))
>>> timeit(fX, number=100)
56.61828187300125

在所有情况下,成本都将由分配十进制 GB 的 RAM 并写入其中的每个字节来决定。 fX 大约比其他三个函数慢两倍,因为它必须执行两次。使用这样的代码时,请记住一个很好的经验法则:最小化分配数量。可能值得使用一种您可以显式控制分配的低级语言(如果您还不知道任何此类语言,我建议 Rust)。

简单,使用序列乘法:

arr = bytearray(b'\x01') * 10 ** 9

相同的方法适用于用零初始化 (bytearray(b'\x00') * 10 ** 9),通常首选这种方法,因为以前将整数传递给 bytes 构造函数一直是混淆的根源(人们有时认为他们可以具有整数值的单个元素 bytes).

您想先初始化单个元素bytearray,然后再乘法,而不是先乘法bytes再传递给bytearray构造函数,这样就避免了峰值内存加倍要求(并且需要从一个巨大的数组读取并写入另一个,在任何解决方案都需要的单个数组上的简单 memset 类操作之上)。

在我的本地测试中,bytearray(b'\x01') * 10 ** 9 的运行速度与 bytearray(10 ** 9) 一样快;每个循环都花费了大约 164 毫秒,而乘以 bytes 对象,然后将其传递给 bytearray 构造函数需要 434 毫秒。