Python while True循环运行久后变慢、方位角差值恒为0问题排查
问题根本诱因
两个故障现象对应独立的根因,和你描述的“初始运行正常、数分钟后异常”特征完全匹配:
- 程序逐渐变慢、单步耗时达数秒:核心原因是串口写缓冲区溢出阻塞。pyserial默认采用阻塞写模式,且未配置写超时阈值,如果Arduino端串口读取速度跟不上Python端发送速度,数据会在发送缓冲区持续堆积,数分钟后缓冲区被完全填满。后续每次执行
port.write()时,程序会强制暂停,等待缓冲区释放足够空闲空间才能写入新数据,阻塞时长从数秒到数十秒不等。程序刚启动时缓冲区为空,因此不会触发阻塞。 - 方位角差值恒为0:由两个逻辑bug共同导致:
- 精度过早截断:你在拿到方位角原始浮点值后第一时间用
int()强转,直接舍弃了小数部分。近地卫星1秒内的方位角变化量经常小于1度,两次浮点值差小于1度时,强转整数后数值完全相等,差值自然为0。 - 未处理循环边界:方位角是0~360度的循环值,当目标从359度移动到1度时,直接做差会得到-358的错误结果,即使精度足够,跨边界场景下计算值也完全不符合实际运动逻辑。
- 精度过早截断:你在拿到方位角原始浮点值后第一时间用
修复方案
按以下步骤调整代码即可解决全部问题:
- 串口初始化时增加写超时配置,启动前清空残留缓冲区,从根源避免无限阻塞:
import serial # 串口初始化,根据实际硬件参数修改端口、波特率 port = serial.Serial( port='COMx', baudrate=9600, write_timeout=1 # 写操作最长阻塞1秒,防止程序卡死 ) # 启动时清空缓冲区残留的无效数据 port.reset_input_buffer() port.reset_output_buffer()
- 调整计算逻辑:采样阶段全程保留浮点精度,差值计算时补全360度边界处理,所有数值计算完成后再转成需要的整数格式,避免提前截断精度。
- 调整循环时序:校准采样间隔,抵消代码执行、串口发送带来的时间漂移,保证两次位置采样的间隔稳定为1秒。
修正后的完整循环代码如下:
import time import math from datetime import datetime degrees_per_radian = 180.0 / math.pi # 以下home、iss对象初始化逻辑和你原有代码保持一致即可 # home = ephem.Observer() # iss = ephem.readtle(...) while True: loop_start_ts = time.time() # 第一次位置采样 home.date = datetime.utcnow() iss.compute(home) el_prev = iss.alt * degrees_per_radian az_prev = iss.az * degrees_per_radian print(f"prev az: {az_prev:.2f}, prev el: {el_prev:.2f}") # 保证两次采样间隔为1秒 time.sleep(1) # 第二次位置采样 home.date = datetime.utcnow() iss.compute(home) el_curr = iss.alt * degrees_per_radian az_curr = iss.az * degrees_per_radian # 正确计算方位角差值,处理0/360度循环边界 az_diff = az_curr - az_prev if az_diff > 180: az_diff -= 360 elif az_diff < -180: az_diff += 360 # 所有计算完成后再转整数,避免精度损失 az_send = int(az_diff) el_send = int(el_curr) print(f"curr az: {az_curr:.2f}, 1s az change: {az_diff:.2f}") # 串口发送增加超时处理,避免缓冲区堆积 str_pos = f"{az_send};{el_send}\n" try: port.write(str_pos.encode()) port.flush() print("data transmitted!") except serial.SerialTimeoutException: port.reset_output_buffer() print("serial write timeout, buffer reset") print("__________________") # 校准循环总时长,保证采样间隔稳定 loop_cost = time.time() - loop_start_ts if loop_cost < 1: time.sleep(1 - loop_cost)
额外优化点
- 确认Arduino端串口读取逻辑的波特率、数据解析格式和Python端完全匹配,解析错误会导致读取速度下降,反向拖慢串口发送链路。
- 长期运行时可以删除冗余的print调试语句,控制台大量持续输出也会带来额外的性能开销。
内容的提问来源于stack exchange,提问作者LUGG4S
相关产品推荐
相关产品推荐

