是否可以使用非零值有效地初始化 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 毫秒。
我需要一个巨大的布尔数组。所有值都应初始化为 "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 毫秒。