Python中快速二进制数据转换

6 投票
2 回答
4570 浏览
提问于 2025-04-17 06:24

在Python中,将二进制数据字符串转换为数字值的最快方法是什么?

我现在使用的是struct.unpack_from(),但是遇到了性能瓶颈。

背景:我正在处理一个混合了二进制和ASCII数据的输入流。ASCII数据的转换是通过C语言和ctypes来完成的。在C中实现解包的性能和使用unpack差不多。我猜是调用的开销太大了。我希望能找到一种类似C语言的原生转换方法(虽然这可能不太符合Python的风格)。很可能这些代码都需要转移到C语言中。

这个流是网络字节序(大端序),而我的机器是小端序。一个示例转换可能是:

import struct
network_stream = struct.pack('>I', 0x12345678)
(converted_int,) = struct.unpack_from('>I', network_stream, 0) 

我对处理流格式不太关心,更关注的是二进制转换的一般情况,以及是否有其他替代unpack的方法。例如,socket.ntohl()需要一个整数,而int()无法将二进制数据字符串转换为整数。

谢谢你的建议!

2 个回答

2

根据我的经验,你说得对,代码确实需要转到C语言。正如你发现的,二进制转换的各种工具(比如 structctypes)在性能上大致相似。

Cython 是为Python生成C扩展的最简单方法。

另一种简单的方法是完全放弃CPython,转而使用 pypy,它可以通过跟踪即时编译(JIT)生成高质量的低级代码。

还有一种更具挑战性但更直接的方法是编写一个普通的C扩展。这并不好玩,但其实也不难。

2

速度问题可能不是出在struct.unpack_from()这个函数本身,而是Python在执行其他操作时需要做的事情,比如查找字典、创建对象、调用函数以及其他任务。如果你直接导入unpack_from,而不是每次都从struct模块里获取,可以稍微加快一点速度,因为这样可以省去一次字典查找。

$ python -m timeit -s "import struct; network_stream = struct.pack('>I', 0x12345678)" "(converted_int,) = struct.unpack_from('>I', network_stream, 0)" 
1000000 loops, best of 3: 0.277 usec per loop

$ python -m timeit -s "import struct; from struct import unpack_from; network_stream = struct.pack('>I', 0x12345678)" "(converted_int,) = unpack_from('>I', network_stream, 0)"
1000000 loops, best of 3: 0.258 usec per loop

不过,如果你需要处理很多解析逻辑,每次都要一个一个地拆解数字,这样就无法一次性处理一整组数据,那么无论你用什么方法来实现,效果都差不多。你可能需要在一些开销更小的语言中完成这个内部循环,比如C语言。

撰写回答