python-can接收CAN数据存在3-5秒延迟,寻求解决方案
问题排查与解决方案
核心延迟原因
- 频繁磁盘I/O:每次循环都调用
df.to_csv()写入CSV,磁盘操作远慢于内存处理,直接阻塞CAN消息接收与处理流程。 - 低效DataFrame更新:重复使用
df.loc[df['Name']=="..."]遍历整个DataFrame查找目标行,增加不必要的计算开销。 - 冗余监听器:
_get_message函数无实际作用,却占用Notifier的处理资源。
修复后的代码
import can import logging import pandas as pd from time import time class PCANBus(object): def __init__(self): logging.info("Initializing CANbus") self.bus = can.interface.Bus(interface='vector', app_name='EA7B', channel='0,1', receive_own_messages=True) self.buffer = can.BufferedReader() # 移除无用的_get_message监听器 self.notifier = can.Notifier(self.bus, [self.buffer]) def read_input(self): return self.buffer.get_message() def cleanup(self): self.notifier.stop() self.bus.shutdown() pcan = PCANBus() fileName = "c:\\Data\\Can.csv" df = pd.read_csv(fileName) # 预计算目标行索引,避免每次遍历整个DataFrame try: target_row_idx = df[df['Name'] == "ADAS_CAM_EGO_LANE_HI_ACCU_POSX"].index[0] except IndexError: logging.error("CSV中未找到目标行'ADAS_CAM_EGO_LANE_HI_ACCU_POSX'") exit(1) # 配置批量写入参数 WRITE_INTERVAL = 1 # 每1秒写入一次CSV last_write_time = time() update_count = 0 try: while True: msg = pcan.read_input() if msg.arbitration_id == 780: # IDAS_30C print("Message value", msg) # 使用预计算索引快速更新单元格 df.at[target_row_idx, 'value'] = str(msg.data[3] >> 1) update_count += 1 # 仅在达到时间间隔且有更新时写入CSV current_time = time() if (current_time - last_write_time >= WRITE_INTERVAL) and update_count > 0: try: df.to_csv(fileName, index=False) last_write_time = current_time update_count = 0 # 重置更新计数器 except PermissionError: print("无法打开文件,跳过本次写入") except KeyboardInterrupt: # 退出时写入剩余更新 if update_count > 0: try: df.to_csv(fileName, index=False) except PermissionError: print("退出时无法写入最终更新到CSV") print("Program Exited") pcan.cleanup()
修复说明
- 移除冗余监听器:删除无实际作用的
_get_message函数,减少Notifier的处理负载。 - 预计算目标行索引:启动时一次性找到目标行的索引,后续使用
df.at[]直接更新单元格,效率远超重复遍历DataFrame。 - 批量写入CSV:设置固定时间间隔(1秒),仅当有更新且达到间隔时才写入磁盘,彻底解决频繁I/O导致的阻塞。
- 退出时收尾:确保程序中断时,未写入的更新能被保存。
额外优化建议
- 如果需要更低延迟,可将CSV写入逻辑放到单独线程,避免阻塞CAN消息接收线程。
- 生产环境中可替换
print()为logging模块,减少控制台输出带来的微小延迟。 - 检查Vector接口的接收缓冲区配置,确保硬件数据能及时传递到软件层。
内容的提问来源于stack exchange,提问作者ash678
相关产品推荐
相关产品推荐

