解决python3 整数数组转bytes的效率问题

解决Python3整数数组转bytes的效率问题可以采用两种方式,分别是原生bytes方法和NumPy库的方式。

原生bytes方法

基础方法

  1. 将整数数组转换成bytes。

使用Python内置函数bytes()可以将整数数组转换为bytes类型,示例如下:

nums = [1, 2, 3, 4]
bytes_data = bytes(nums)

这样就可以将整数数组 [1, 2, 3, 4] 转换为bytes类型。

  1. 使用struct模块打包成字节流

struct模块可以将Python中的数据类型转化为C中的数据类型,从而实现字节流的打包和解包。其中,pack函数是将数据转化为字节流,unpack函数是将字节流转化为数据。

如对于以下整数数组转换为bytes:

nums = [1, 2, 3, 4, 255]
byte_array = bytearray(struct.pack('>' + 'I' * len(nums), *nums))

其中 ">" 是大端模式(网络字节序),"I" 表示4字节的无符号整型。一定要将所有的nums元素都打包传入。

  1. 使用memoryview方法

memoryview() 函数返回给定参数的内存查看对象(memoryview对象),这个对象允许Python代码在没有复制内容的情况下访问Python对象的内部数据。

arr = [1, 2, 3, 4, 255]
b = bytes(memoryview(arr).cast('B'))

其中,memoryview() 函数接可写入任何对象,它的 cast() 方法可以强制用指定类型的项构造一个新的 memoryview 对象。

但是,当元素的数值超过256时,会自动模256,因此需要在解析时使用函数bytesub:

def bytesub(byte_array: bytes):
    return bytes((x % 256) for x in byte_array)

arr = [1, 2, 3, 4, 255]
b = bytesub(memoryview(arr).cast('B'))

优化

  1. 在原生bytes方法中,使用bytes()在转换大型数组时会生成临时Python对象。这在大型数组上可能会更慢并且占用更多内存。因此,我们可以使用 bytearray() 消除额外的对象复制:
nums = [1, 2, 3, 4, 255]
b = bytearray()
b.extend(nums)
  1. 使用数组模块 array,从而避免了字节复制:
import array
nums = [1, 2, 3, 4, 255]
b = array.array('B', nums).tobytes()

NumPy库的方法

对于大型数组进行转换,NumPy库的速度和效率更高。这个NumPy库的主要数据类型是ndarray,是一个高效、多维数组,提供了与 C/C++ 数组的快速访问和转换所需的基本类型的大小和字节序。它可以将整数数组以高效方式转换为 bytes 类型。具体步骤如下:

  1. 创建一个 NumPy 数组:
import numpy as np
nums = np.array([1, 2, 3, 4, uint8(255)], dtype=np.uint8)  
  1. 其中, dtype=np.uint8 是一个关键点。在计算机界中,编码信息的最小单元是 8 位,所以使用 uint8 就可以明确地表示 0~255,避免了无关的向下取整,同时物尽其用。

  2. 转换为字节流:

np_data = np.array(nums).tobytes()

或者使用:

np_data = nums.tobytes()

示例

示例1:使用原生bytes方法转换一个8192整数长的数组,使用timeit函数比较字节数量及其对应时间

使用以下方法将8192位整数数组转换为字节流,bytes() 方法生成的临时对象数目 ~ 8192 * 8,可能很耗时。实际经过时间检查,可以看到其花费了大约 0.061秒:

from array import array
import timeit

NUMS = array('L', range(8192));

def bytes_loop():
    b = bytearray()
    for num in NUMS:
        b.append(num & 0xff)
        b.append(num >> 8 & 0xff)
        b.append(num >> 16 & 0xff)
        b.append(num >> 24 & 0xff)
    return bytes(b)

def bytes_loop_pruned():
    b = bytearray(len(NUMS) * 4)
    index = 0
    for num in NUMS:
        b[index] = num & 0xff
        b[index + 1] = num >> 8 & 0xff
        b[index + 2] = num >> 16 & 0xff
        b[index + 3] = num >> 24 & 0xff
        index += 4
    return bytes(b)

def bytes_method():
    return bytes(NUMS)

N = 1000
print(timeit.timeit(bytes_loop, number=N))
print(timeit.timeit(bytes_loop_pruned, number=N))
print(timeit.timeit(bytes_method, number=N))

结果:

6.922980099391505
1.2628497272736984
0.009422727272909193

示例2:使用 NumPy 库来解决相同的缓慢性能

考虑以下示例:

import numpy as np
from array import array
import timeit

NUMS = np.array(array('L', range(8192)), dtype=np.uint32)

def numpy_method():
    return NUMS.tobytes()

def original_bytes_method():
    items = list(NUMS)
    return bytes(memoryview(items))

N = 1000
print(timeit.timeit(numpy_method, number=N))
print(timeit.timeit(original_bytes_method, number=N))

该代码与前一示例非常相似 - 均针对8192个元素为32位的数组。与原始bytes()方法和array.array()相比,numpy.tobytes()方法使用的实际内存减少了某些“再次分段”的重新分配开销。结果:

0.008493032778605789
9.399150620732546

可以看到在将大量整数转换为字节流的时候,numpy可以比原生bytes方法快得多。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:解决python3 整数数组转bytes的效率问题 - Python技术站

(1)
上一篇 2023年5月31日
下一篇 2023年5月31日

相关文章

  • python添加模块搜索路径方法

    添加模块搜索路径是在Python中很常见的操作,可以让我们很方便地引用自己编写的模块或第三方模块。 下面介绍两种添加模块搜索路径的方法: 方法一:sys.path.append() 在Python中,我们可以使用sys.path来查看当前Python解释器的所有模块搜索路径。我们可以使用sys.path.append()方法来添加自己的模块搜索路径。 imp…

    python 2023年6月3日
    00
  • python如何解决指定代码段超时程序卡死

    在Python中,有时候我们会遇到一些代码段执行时间过长,导致程序卡死的情况。这种情况下,我们需要使用一些技巧来解决这问题。本文将介绍如何使用Python的一些库来解决这个问题。 使用signal库 signal库是Python中的一个标准库,它可以用来处理各种信号。我们可以使用signal库来设置一个定时器,当定时器超时时,就会向进程发送一个SIGALRM…

    python 2023年5月13日
    00
  • python利用百度AI实现文字识别功能

    Python利用百度AI实现文字识别功能 前言 百度AI开放平台提供了多种类型的API,其中文字识别API是非常实用的一种,它可以将多种形式的文字图片转换成文本,便于后续处理。本文将介绍如何使用百度AI实现Python文字识别功能。 准备工作 登录百度AI开放平台,创建自己的应用,获取APP_ID、API_KEY、SECRET_KEY信息; 安装Python…

    python 2023年5月18日
    00
  • Python出现segfault错误解决方法

    Python出现segfault错误解决方法 在Python中,segfault错误通常是由于内存访问错误或其他底层问题导致的。当Python解释器遇到segfault错误时,程序将崩溃并退出。本文将介绍一些常见segfault错误及其解决方法。 解决方法1:更新Python版本 如果您的Python版本过旧,可能会导致segfault错误。解决是更新Pyt…

    python 2023年5月13日
    00
  • 零基础写python爬虫之使用Scrapy框架编写爬虫

    下面是详细讲解“零基础写python爬虫之使用Scrapy框架编写爬虫”的完整攻略: 一、Scrapy框架介绍 Scrapy是一个支持Python 2 & 3的快速、高效的web爬虫框架。通过它,用户可以简单地更改参数来创建新的spider(爬虫)。Scrapy框架具备高度的reusability和灵活性。 二、Scrapy框架的安装 Scrapy安…

    python 2023年5月13日
    00
  • Python requests用法和django后台处理详解

    以下是关于Python requests用法和Django后台处理的详细攻略: Python requests用法 Python requests是一个流行的HTTP库,用于向Web服务器发送HTTP请求和接收响应。以下是Python requests的基本用法: 安装requests库 在使用requests库之前,需要先安装它。可以使用以下命令在终端中安…

    python 2023年5月14日
    00
  • python的sys.path模块路径添加方式

    添加模块搜索路径是Python程序中经常遇到的问题之一。在Python中,可以通过在sys模块中的path列表中查找模块。默认情况下,sys.path是继承自环境变量PYTHONPATH以及Python安装的标准库的目录。但是,我们也可以添加自定义的模块路径到sys.path中,以便Python可以在这些自定义路径中查找模块。 以下是添加python模块路径…

    python 2023年6月2日
    00
  • pip install urllib2不能安装的解决方法

    安装 urllib2 库时,有可能会出现 pip install urllib2 命令不能安装的情况。这与 Python 版本以及所在的操作系统有关。下面讲解如何解决这个问题。 解决方法 方法一:使用 Python 2.x urllib2 库是 Python 2.x 系列的一个标准库,所以在 Python 2.x 系列中,可以直接使用 import urll…

    python 2023年6月3日
    00
合作推广
合作推广
分享本页
返回顶部