Python中的快速二进制数据转换

时间:2011-11-16 00:33:54

标签: python

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

我正在使用struct.unpack_from(),但是达到了性能限制。

上下文:传入流是混合二进制和ASCII数据。 ASCII数据转换是通过ctypes在C中完成的。通过ctypes在C中实现解包产生了与解包相似的性能。我的猜测是呼叫开销太大了。我希望找到一种原生的类C强制方法(但不是Pythonic)。很可能所有这些代码都需要转移到C.

流是网络字节顺序(big-endian),机器是little-endian。转换的示例如下:

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

我不太关心处理流格式,而不是二进制转换的一般情况,如果甚至有unpack的替代方案。例如,socket.ntohl()需要一个int,int()不会转换二进制数据字符串。

感谢您的建议!

2 个答案:

答案 0 :(得分:2)

根据我的经验,您是正确的,需要将代码移动到C.正如您发现各种二进制转换工具的性能( struct ctypes 例如)具有大致相似的性能。

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

另一个简单的方法是放弃CPython,完全支持pypy,它可以使用跟踪JIT生成高质量,低级别的代码。

更具挑战性但更直接的方法是编写普通的C扩展。这不好玩,但并不困难。

答案 1 :(得分: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 来消除其中一个字典查找,您可以稍微加快速度:

{{1}}

但是,如果需要大量的解析逻辑,需要一次解包一个数字,并且不会打算批量解包整个数据,那么你所要求的是什么并不重要您。您可能需要在开销较少的语言中完成整个内部循环,例如C。