You need to enable JavaScript to run this app. 如何用Matplotlib实现Binance WebSocket ETHUSDT数据非阻塞实时绘图
优惠活动
大模型
产品
解决方案
定价
更多

如何用Matplotlib实现Binance WebSocket ETHUSDT数据非阻塞实时绘图

阻塞问题核心成因

原代码的阻塞问题由两个逻辑缺陷直接导致:

  • 每收到一条WebSocket消息就调用plt.show(),该函数默认运行在阻塞模式下,会暂停整个进程的执行,直到手动关闭弹出的图表窗口,完全中断了WebSocket的持续消息接收流程。
  • 每次收到数据就重新执行plt.plot()创建新的绘图元素,没有复用已有的画布、坐标轴资源,既会生成冗余的图形对象,也无法实现“单张图表持续更新”的实时绘图效果。
无阻塞实时绘图调整方案
  • 开启Matplotlib交互模式,替代默认的阻塞绘图逻辑
    调用plt.ion()切换为交互绘图模式,该模式下创建的绘图窗口不会卡住后续代码执行,可通过手动触发短暂停实现界面刷新。
  • 提前初始化可复用的绘图对象
    程序启动阶段就创建好画布、坐标轴、折线图形的空对象,后续收到新数据仅需更新折线的数据源,无需重复创建绘图元素。
  • 拆分线程规避跨线程UI操作
    Matplotlib的绝大多数绘图后端都不支持跨线程安全操作,将WebSocket的长连接接收逻辑放到独立子线程运行,主线程专门负责绘图刷新,可彻底避免绘图卡顿、闪退问题。
  • 限制数据缓存长度
    为收盘价数组设置最大缓存长度(比如匹配原代码x轴的1000个点上限),避免长期运行后数据量过大导致绘图性能下降。
调整后的可运行代码
import websocket, json
import matplotlib.pyplot as plt
import numpy as np
import threading

TRADE_SYMBOL = "ETHUSDT"
SOCKET = "wss://stream.binance.com:9443/ws/ethusdt@kline_1m"
# 匹配原x轴设置的最大数据缓存长度
MAX_DATA_LENGTH = 1000
closes = []

# 初始化绘图配置
plt.ion()
fig, ax = plt.subplots(figsize=(10, 6))
price_line, = ax.plot([], [], linewidth=2)
ax.set_xlim(0, MAX_DATA_LENGTH)
# 根据ETH常规价格区间设置初始y轴范围
ax.set_ylim(3000, 5000)

def on_message(ws, message):
    global closes
    parsed_msg = json.loads(message)
    kline_data = parsed_msg['k']
    close_price = float(kline_data['c'])
    # 更新收盘价缓存,超出长度则丢弃最早的数据
    closes.append(close_price)
    if len(closes) > MAX_DATA_LENGTH:
        closes.pop(0)

def run_websocket():
    ws = websocket.WebSocketApp(SOCKET, on_message=on_message)
    ws.run_forever()

if __name__ == "__main__":
    # 启动WebSocket接收子线程,设置为守护线程,主程序退出时自动回收
    ws_thread = threading.Thread(target=run_websocket, daemon=True)
    ws_thread.start()

    # 主线程循环刷新绘图,窗口关闭时自动退出
    while plt.fignum_exists(fig.number):
        # 更新折线图的数据源
        data_len = len(closes)
        price_line.set_xdata(np.arange(data_len))
        price_line.set_ydata(closes)
        # 自适应调整y轴范围,给数据留少量展示边距
        if data_len > 0:
            min_price = min(closes)
            max_price = max(closes)
            ax.set_ylim(min_price * 0.999, max_price * 1.001)
        # 触发界面重绘
        fig.canvas.draw_idle()
        # 20ms短暂停驱动界面刷新,不会造成长阻塞
        plt.pause(0.02)
长期运行注意事项
  • 不要在WebSocket的消息回调函数中直接调用Matplotlib绘图接口,回调函数运行在独立子线程,直接操作UI会触发未知的卡顿或崩溃。
  • 无需在交互模式下手动调用plt.show(),通过循环内的plt.pause()即可持续驱动界面刷新。
  • 可根据实际需求调整MAX_DATA_LENGTH和y轴自适应的边距比例,兼顾展示效果和性能。

内容的提问来源于stack exchange,提问作者roadrunner38

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.09 07:15:08