【问题标题】:Is it possible to effectively initialize bytearray with non-zero value?是否可以用非零值有效地初始化字节数组?
【发布时间】:2016-11-30 13:25:43
【问题描述】:

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

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

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

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

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

我知道我可以用零初始化 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

【问题讨论】:

    标签: python python-3.x python-bytearray


    【解决方案1】:

    简单,使用序列乘法:

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

    同样的方法也适用于用零初始化 (bytearray(b'\x00') * 10 ** 9),而且它通常是首选,因为将整数传递给 bytes 构造函数之前一直是混乱的根源(人们有时认为他们可以制作单个元素 bytes与整数的值)。

    您希望先初始化单个元素 bytearray,然后再进行乘法运算,而不是先将 bytes 乘以并将其传递给 bytearray 构造函数,这样您就可以避免将峰值内存需求加倍(并且需要从一个巨大的除了任何解决方案都需要对单个数组进行简单的memset-like 操作之外,还可以写入另一个数组。

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

    【讨论】:

    • 这是一个很好的解释,应该是首选的解决方案。
    【解决方案2】:

    考虑将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)。

    【讨论】:

    • 除了%timeit,这是我之前回答的副本。
    【解决方案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'
    

    更多详情请见this answer。

    【讨论】:

      猜你喜欢
      • 2013-10-06
      • 2016-03-03
      • 1970-01-01
      • 2012-09-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-29
      相关资源
      最近更新 更多