You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修改plot_own.py以适配带1ms写入延迟的低速率数据流生成脚本gen_own.py

如何修改plot_own.py以适配带1ms写入延迟的低速率数据流生成脚本gen_own.py

我来帮你解决这个问题!从你的输出能明显看出来,核心问题是原来的plot_own.py默认每次都能读到完整的64字节数据行,但gen_own.py写数据的速度变慢后,脚本读取时经常拿到不完整的内容(甚至是空的),导致split()操作失败抛出异常。下面是具体的修改方案和详细解释:

问题根源分析

  • 原get_data函数每次打开文件后直接跳到末尾,固定读取64字节。但gen_own.py每1ms才会写入一行完整数据(约64字节),当plot脚本的动画循环触发时,可能文件里还没有新的完整行,或者刚写入了一部分内容,导致读到的内容无法分割成有效的x和y值。
  • 频繁打开/关闭文件不仅增加开销,还无法记住上次读取的位置,容易出现重复读取或漏掉数据的情况。

具体修改方案

我们需要调整读取逻辑,确保只处理完整的数据行,同时跟踪上次读取的位置,避免重复或遗漏。下面是修改后的完整plot_own.py代码,关键修改点我会单独标注:

#!/usr/bin/env python3

import io
import time
import matplotlib.pyplot as plt
import matplotlib as mpl
import matplotlib.animation

DATA_FILENAME = "data.txt"
PLOT_LIMIT = 20
ANIM_FILENAME = "video.gif"

fig, ax = plt.subplots(1, 1, figsize=(10,8))
ax.set_title("Plot of random numbers from `gen_own.py`")
ax.set_xlabel("time / s")
ax.set_ylabel("random number / #")
ax.set_ylim([0, 1])

# 关键修改1:全局维护文件句柄和上次读取位置,避免重复打开文件
file_handle = open(DATA_FILENAME, "r")
last_read_pos = 0

def get_data():
    global last_read_pos
    # 从上次读取的位置开始读取新增内容,而非直接跳到文件末尾
    file_handle.seek(last_read_pos)
    raw_data = file_handle.read()
    # 更新读取位置到当前文件末尾
    last_read_pos = file_handle.tell()
    
    # 关键修改2:按行分割数据,过滤掉不完整的行和空行
    lines = raw_data.strip().split("\n")
    # 如果最后一行是空的(比如刚写入换行但还没写数据),直接丢弃
    if lines and not lines[-1]:
        lines.pop()
    return lines

def animate(i, xs, ys, limit=PLOT_LIMIT, verbose=False):
    try:
        # 现在get_data返回的是完整数据行的列表
        new_lines = get_data()
        for line in new_lines:
            if not line:
                continue
            x, y = map(float, line.split())
            # 确保时间递增,避免重复处理旧数据
            if not xs or x > xs[-1]:
                xs.append(x)
                ys.append(y)
                # 限制列表长度,保持图表只显示最新的PLOT_LIMIT条数据
                xs = xs[-limit:]
                ys = ys[-limit:]
            else:
                print(f"W: {time.time()} :: STALE!")
        if verbose and new_lines:
            print(new_lines)
    except ValueError as e:
        print(f"W: {time.time()} :: EXCEPTION! {str(e)}")
    else:
        # 关键修改3:只有有新数据时才更新图表,避免无效重绘
        if xs and ys:
            ax.clear()
            ax.set_ylim([0, 1])
            ax.plot(xs, ys)
            # 重新设置标题和轴标签,避免clear后丢失
            ax.set_title("Plot of random numbers from `gen_own.py`")
            ax.set_xlabel("time / s")
            ax.set_ylabel("random number / #")

# 关键修改4:初始化xs和ys为空列表,避免初始值干扰判断
anim = mpl.animation.FuncAnimation(fig, animate, fargs=([], []), interval=5)
plt.show()

# 关闭文件句柄
file_handle.close()
plt.close()

修改点详细说明

  1. 持久化文件句柄:把文件打开操作放在全局,避免每次读取都重复打开/关闭文件,同时用last_read_pos记录上次读到的位置,确保每次只读取新增的内容。
  2. 读取完整行:不再固定读取64字节,而是读取所有新增数据后按行分割,过滤掉不完整的行(比如文件末尾还没写完的半行),彻底解决split()失败的问题。
  3. 支持多行处理:允许一次读取多行数据(如果把动画间隔设为5ms,可能一次读到5行),遍历每一行处理,保证所有新数据都能被添加到图表中。
  4. 优化初始值:把xs和ys的初始值改为空列表,避免原来的初始时间和None值带来的判断与绘图问题。
  5. 减少无效重绘:只有当有新数据时才更新图表,避免每次循环都清空重绘,提升脚本运行效率。

额外建议

  • 可以把动画interval从1ms调整到5-10ms,1ms的循环过于频繁会占用过多CPU资源,而gen_own.py每1ms才写一行数据,5ms的间隔完全能覆盖所有新数据。
  • 测试时建议先启动gen_own.py,再运行plot_own.py,确保文件已经存在且有数据在写入。

备注:内容来源于stack exchange,提问作者ecjb

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.15 09:23:05