使校验和功能更快
Make checksum function faster
这个校验和计算会被调用很多次:是否可以让下面的校验和函数运行得更快?
我特别想知道是否有可能摆脱 for 循环(因为有人告诉我它们在 python 中很慢)。
sred = b'Standa\x00\x00\x00\x00\x00\x00\x00\x00\x00\x008MR191-28'\
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
b'\x00\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc'\
b'\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xe9\xa8'
def _check_crc(bstring):
crc = 0xffff
for b in bstring:
crc = crc ^ b
for i in range(8):
carry_flag = crc & 0x0001
crc = crc >> 1
if carry_flag == 1:
crc = crc ^ 0xa001
return crc
_check_crc(sred) # will give 0
这段代码在我的机器上快了大约 10%:
def _check_crc(bstring):
crc = 0xffff
for b in bstring:
crc = crc ^ b
for i in range(8):
if crc & 0x0001:
crc = (crc >> 1) ^ 0xa001
else:
crc = crc >> 1
return crc
这主要是由于取消了对 carry_flag
的分配。布尔比较 if crc & 0x0001:
也可能比比较 1.
快一点
可能还有其他可能的改进,但我现在唯一的进一步想法是尝试在 C 中实现该功能。但是,我不知道这会快多少。按位运算应该已经相当快了。
最快的方法可能是使用 65536 条目查找 table;类似于:
def _check_crc(bstring):
crc = 0xFFFF00
for b in bstring:
crc = lookupTable[crc | b]
return crc >> 8
注意:我将 CRC 和 table 中的所有值“pre-shifted”向左 8 位,以移除循环中间的移位(而不是 table =11=]).
table/list 本身可以是 run-time 生成的,或者是显式的(例如,通过打印出 run-time 生成的列表并将其直接剪切并粘贴到您的源代码中)。我太懒了(并且不记得足够 Python)来显示 run-time 代的示例代码。
我发现这是一个众所周知的算法 (crc16-modbus),并且有 python 模块 (libscrc) 可用于计算校验和。我测试了它,它比我发布的原始代码快得多。
这个校验和计算会被调用很多次:是否可以让下面的校验和函数运行得更快?
我特别想知道是否有可能摆脱 for 循环(因为有人告诉我它们在 python 中很慢)。
sred = b'Standa\x00\x00\x00\x00\x00\x00\x00\x00\x00\x008MR191-28'\
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\
b'\x00\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc'\
b'\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xe9\xa8'
def _check_crc(bstring):
crc = 0xffff
for b in bstring:
crc = crc ^ b
for i in range(8):
carry_flag = crc & 0x0001
crc = crc >> 1
if carry_flag == 1:
crc = crc ^ 0xa001
return crc
_check_crc(sred) # will give 0
这段代码在我的机器上快了大约 10%:
def _check_crc(bstring):
crc = 0xffff
for b in bstring:
crc = crc ^ b
for i in range(8):
if crc & 0x0001:
crc = (crc >> 1) ^ 0xa001
else:
crc = crc >> 1
return crc
这主要是由于取消了对 carry_flag
的分配。布尔比较 if crc & 0x0001:
也可能比比较 1.
可能还有其他可能的改进,但我现在唯一的进一步想法是尝试在 C 中实现该功能。但是,我不知道这会快多少。按位运算应该已经相当快了。
最快的方法可能是使用 65536 条目查找 table;类似于:
def _check_crc(bstring):
crc = 0xFFFF00
for b in bstring:
crc = lookupTable[crc | b]
return crc >> 8
注意:我将 CRC 和 table 中的所有值“pre-shifted”向左 8 位,以移除循环中间的移位(而不是 table =11=]).
table/list 本身可以是 run-time 生成的,或者是显式的(例如,通过打印出 run-time 生成的列表并将其直接剪切并粘贴到您的源代码中)。我太懒了(并且不记得足够 Python)来显示 run-time 代的示例代码。
我发现这是一个众所周知的算法 (crc16-modbus),并且有 python 模块 (libscrc) 可用于计算校验和。我测试了它,它比我发布的原始代码快得多。