7

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

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

但是像上面那样创建它需要太多的内存。所以我决定使用bytearray它:

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

是否可以像初始化bytearray一样b'\x01'有效地初始化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
4

3 回答 3

11

简单,使用序列乘法:

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对象乘以 434 毫秒,然后将其传递给bytearray构造函数。

于 2016-11-30T13:47:39.423 回答
4

考虑将NumPy用于此类事情。在我的计算机上,使用布尔“dtype”(初始化一个全为 1 值的数组)与裸构造函数np.ones一样快: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)。

于 2016-11-30T13:32:01.570 回答
3

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

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

回报:

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'

有关更多详细信息,请参阅此答案

于 2016-11-30T13:29:04.587 回答