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

yizhihongxing

解决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实现半自动化发送微信信息”的完整攻略,包括以下几个步骤: 安装itchat库 扫码登录微信 获取好友列表 发送文本信息 发送图片信息 详细说明如下: 1. 安装itchat库 itchat是一个开源的微信个人号接口,使用Python调用微信从未如此简单。可以使用pip在命令行中安装,如下所示: pip install itc…

    python 2023年5月18日
    00
  • 解决python -m pip install –upgrade pip 升级不成功问题

    下面是详细讲解“解决python-mpipinstall–upgradepip升级不成功问题”的完整攻略。 问题描述 在使用Python时,我们可能会遇到需要升级pip工具的情况,常见的做法是使用pip install –upgrade pip命令进行升级,但有时候该方法却不能成功升级pip,下面我们就来解决这个问题。 解决方法 方法一:使用Python…

    python 2023年5月14日
    00
  • 如何在Python中插入Redis数据库中的数据?

    以下是在Python中插入Redis数据库中的数据的完整使用攻略。 使用Redis数据库的前提条件 在使用Python连接Redis数据库之前,需要确保已经安装Redis数据库,并已经启动Redis服务器,需要安装Python的Redis驱动redis-py。 步骤1:导入模块 在Python中使用redis模块连接Redis数据库。以下是导入redis模块…

    python 2023年5月12日
    00
  • 关于反爬虫的一些简单总结

    关于反爬虫的一些简单总结 什么是反爬虫? 反爬虫(Anti-Spider)是指防止爬虫程序(Spider)对网站进行自动化抓取的过程。因为一些恶意的爬虫程序可能会对网站造成负面影响,如访问量过大导致服务器崩溃、数据的泄露等,所以很多网站都会采取一些反爬虫策略来避免这种情况的发生。 反爬虫的常见做法 1. User-Agent检测 User-Agent是浏览器…

    python 2023年5月14日
    00
  • 用python批量解压带密码的压缩包

    首先,在Python中我们可以使用zipfile模块来处理压缩文件。zipfile模块提供了ZipFile和ZipInfo两个核心类,可以用来解析和处理zip压缩文件。 接下来是具体步骤: 导入库 import zipfile 创建ZipFile对象,打开压缩包 zip_file = zipfile.ZipFile(‘file.zip’) 打开压缩包中的某个…

    python 2023年6月3日
    00
  • Python实现文件按照日期命名的方法

    Python实现文件按照日期命名的方法,可以使用Python内置模块datetime和os来实现。 1.首先,导入datetime和os模块: import datetime import os 2.使用datetime模块获取当前日期: current_date = datetime.datetime.now().strftime("%Y-%m-…

    python 2023年6月2日
    00
  • python logging模块的使用详解

    Python logging模块的使用详解 什么是logging模块 Python的logging模块提供了大量的灵活方式记录程序运行时产生的信息,包括日志级别、输出位置、日志文件格式等。 利用logging模块可以高效的管理日志,对于排查问题和系统运维等方面非常重要。 logging模块的使用方法 logging模块主要包括四个组件:Logger, Han…

    python 2023年5月31日
    00
  • 如何通过命令行进入python

    当你在命令行终端中打开Python解释器时,你可以输入Python代码并立即查看结果。下面是进入Python解释器的两种方法。 方法一:直接运行Python命令 在终端中输入python命令,即可进入Python交互式模式。 $ python Python 3.8.5 (default, Jan 27 2021, 15:41:15) [GCC 9.3.0] …

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