Python中bytes转int32_t列表的更高效实现及耗时差异疑问
需求与现有实现
需求:将从外部ADC通过以太网接收的原始bytes数据,转换为带符号int32_t格式并存储到列表中。
现有两种实现及1000次迭代测试数据:
方法一(numpy实现)
tempADC = np.ndarray(256, np.intc, rawADC).tolist()
注:rawADC为原始字节数据(示例:
b'T\x08\x00\x00W\xf2\xff\xff\xfe....'),执行后得到256个int32_t值。
测试结果:均值=20微秒,最大值=1130微秒
方法二(原生Python循环实现)
ln = int(len(rawADC)/4) tadc = [0]*256 # 预分配列表缓冲区 for i in range(ln): tadc[i] = int.from_bytes(rawADC[i:(i+4)], byteorder='little', signed=True)
测试结果:均值=181微秒,最大值=1150微秒
疑问解答
1. 是否存在更高效的实现方法?
方法一的numpy实现已经非常高效,底层是C级别的运算,远快于原生Python循环。如果要进一步优化,可以尝试以下两种方案:
优化numpy调用方式:使用
np.frombuffer直接从字节数据创建数组,代码更简洁且性能相当:tempADC = np.frombuffer(rawADC, dtype=np.int32).tolist()(注:
np.intc通常等价于np.int32,直接指定np.int32会更明确)使用struct模块:struct的
unpack方法也是C实现,性能与numpy接近,适合不需要numpy依赖的场景:import struct tempADC = list(struct.unpack('<256i', rawADC))这里
<表示小端字节序,256i表示解析256个带符号int32值,刚好匹配需求。
如果业务场景允许不转换为列表,直接使用numpy数组或struct返回的元组,能进一步省去tolist()的开销,性能会更优。
2. 耗时均值与最大值差异较大是否因双线程导致?
是的,这是多线程环境下的典型现象。
当程序运行在双线程模式时,操作系统的线程调度机制会随时抢占当前线程的CPU时间片,分配给另一个线程执行。如果某次转换操作恰好遇到其他线程占用大量CPU资源(或执行IO阻塞类操作导致调度延迟),当前转换线程就会被暂时挂起,从而导致单次耗时大幅飙升(从几十微秒到1ms以上)。
此外,偶尔的内存碎片整理、系统级别的后台任务也可能导致单次耗时波动,但结合两种方法的最大值都接近1.1ms,线程调度是最主要的诱因。
内容的提问来源于stack exchange,提问作者WITC

