将int拆分为字节的快速方法

时间:2016-03-07 15:33:52

标签: python python-3.x

如果我有一个适合32位的int,那么在python中将它分成4个8位值的最快方法是什么?我的简单时序测试表明,位掩码和移位比divmod()要快一些,但我很确定我没有考虑过所有内容。

>>> timeit.timeit("x=15774114513484005952; y1, x =divmod(x, 256);y2,x = divmod(x, 256); y3, y4 = divmod(x, 256)")
0.5113952939864248
>>> timeit.timeit("x=15774114513484005952; y1=x&255; x >>= 8;y2=x&255; x>>=8; y3=x&255; y4= x>>8")
0.41230630996869877

在你问之前:这个操作会被大量使用。我正在使用python 3.4。

2 个答案:

答案 0 :(得分:7)

如果您正在做很多事情,最快的方法是创建专门的Struct instance专用pack方法并预绑定:

# Done once
int_to_four_bytes = struct.Struct('<I').pack

# Done many times (you need to mask here, because your number is >32 bits)
y1, y2, y3, y4 = int_to_four_bytes(x & 0xFFFFFFFF)

直接使用struct.pack会在首次使用后使用缓存的Struct对象,但每次都要支付缓存查找成本,从格式字符串到缓存Struct,这是次优的。通过创建和预绑定pack Struct对象(在CPython中用C实现),可以绕过实际函数调用之外的所有Python字节代码执行,并且不会花时间进行缓存查找。在我的机器上,它运行大约205 ns,而移位和掩码运行267 ns(没有重新分配x)。

另一种方法(对于更一般的,而不是struct兼容尺寸)正在使用int.to_bytes;例如,在这种情况下:

y1, y2, y3, y4 = (x & 0xFFFFFFFF).to_bytes(4, 'big')

与手动移位和屏蔽方法所花费的时间大致相同(每个循环需要268 ns),但可以更好地扩展到更大的字节数。

答案 1 :(得分:1)

如果你需要非常快的东西,你应该考虑写一个C扩展(见this)。您可以使用或不使用cython来执行此操作。 如果你写了很多这些,我绝对建议你看看cython。

这种类型的东西正是Python非常棒的东西:你可以直接在C中编写速度关键组件,它将与你的python代码(几乎)无缝地交互。