Python实现IsoTP协议时,如何中断CAN阻塞读取以优化传输时延?
Python IsoTP协议模块开发中的时延优化问题
我是Python IsoTP协议实现模块的开发者,IsoTP是基于CAN(ISO-15765)的汽车半双工协议,会将长帧拆分为多个CAN小报文,收发双方需频繁切换角色。
第一版实现的局限
第一版仅实现协议逻辑,由用户处理时序,示例代码如下:
proto.send(...) while proto.is_transmitting(): proto.process() time.sleep(0.01)
此方案要求CAN层配置为非阻塞读取,虽简单但时延表现差,在ECU刷写等大数据传输场景存在问题,sleep会导致传输方向切换时产生时间片延迟。
线程模型的改进与遗留问题
后续改进为线程模型:协议逻辑运行在工作线程中,通过Python Queue与用户线程交互,CAN层采用阻塞读取,控制消息的方向切换时延表现优异,但仍存在未解决的问题:
当用户调用send()时,会将负载写入Queue,工作线程读取队列后启动逻辑,依赖CAN阻塞读取在CAN帧传输期间释放CPU。但当接收完完整IsoTP帧且用户发送队列无数据时,工作线程会进入CAN阻塞读取状态;而用户常在接收响应后立即发送新帧,此时需等待阻塞读取超时(如Windows下典型的16ms)才能处理新数据。
典型业务流程示例
cursor=0 chunk_size=128 while cursor < len(firmware): proto.send(firmware[cursor:cursor+chunk_size]) # write to the tx queue response = proto.recv(timeout=2) # wait for the thread to write to the rx queue if not response.accepted: raise RuntimeError("Flashing failed") cursor+=chunk_size
这种“收到响应后才入队下一帧”的逻辑,会导致工作线程进入阻塞读取状态,超时后才启动新传输。以1MiB固件、128字节分片为例,8192次超时将浪费约131秒。
已构思的解决方案
- 要求用户提前入队多块数据,若某块被ECU拒绝则取消传输;
- 接收帧后添加自旋等待,为用户线程入队留时间,但会浪费CPU;
- 将协议逻辑拆分为收发两个线程,需大量同步机制,复杂度高;
- 新增第二个线程专门读取CAN数据并写入队列,工作线程改为阻塞读取该队列;用户
send()可注入“唤醒”对象触发工作线程,此为当前最优候选方案。
理想方案是像Unix原生支持的那样发送信号中断阻塞读取,但Python的可移植信号机制存疑,且用户可自定义CAN读取函数,可能不兼容信号。
请问是否存在其他可中断阻塞读取、优化传输时延的方案?(目标是消除下图中的红色延迟)

内容的提问来源于stack exchange,提问作者user2302957
相关产品推荐
相关产品推荐

