最近有同学在交流群问我:用 Python 拉港股实时数据,为什么总抛出 timeout,明明 Wi‑Fi 信号满格。我回想当初帮一家投顾工作室做盘中监控,也撞过一模一样的墙。今天我就以「复盘笔记」的形式,把这套排查流程和根治方案分享出来,你可以跟着步骤操作。
一、先搞清楚超时到底卡在哪里
第一步永远是分而治之。我习惯先问两个问题:
- 请求发出去了吗?如果服务端压力大,线程池耗尽,连接建立本身就超时。
- 收到响应了吗?如果数据回来了,但解析 JSON 或写库时程序卡住,上层照样报 timeout。
很多朋友只盯着第一个,忽略了本地消费速度。当一次订阅超过 50 只港股时,同步处理很容易成为隐性瓶颈。
二、为什么不建议频繁 HTTP 轮询
如果你还在用 requests.get 每 3 秒拉一次快照,在港股开盘那段交投活跃期,服务端网关极可能对你的 IP 做频率限制。每新增一只股票,就多一次往返开销,叠加起来超时概率呈指数上升。而且 HTTP 是无状态,每次都要携带完整的认证和请求头,白白消耗带宽。
三、用 WebSocket 建立一条持久通道
我让投顾工作室全面迁移到 WebSocket。原理很简单:只需一次握手,服务端就会持续把每一笔 tick 推给你,不用反复“敲门”。以我常用的 ALLTICK API 实时行情接口为例,它提供基于 WebSocket 的港股推送,你只需在连接成功后发送一次订阅列表,就可以坐等数据流。
import websocket
import json
def on_message(ws, message):
data = json.loads(message)
print(data) # 收到的实时行情直接打印,也可以放到队列或数据库
def on_open(ws):
subscribe_data = {
"action": "subscribe",
"symbols": ["00700.HK", "09988.HK"] # 订阅股票列表
}
ws.send(json.dumps(subscribe_data))
ws = websocket.WebSocketApp(
"wss://api.alltick.co/ws/stock",
on_message=on_message,
on_open=on_open
)
ws.run_forever()
这样一来,请求超时的源头直接被绕开了。
四、订阅也别一口气全扔进去
一次性把 100 只股票全丢给 WebSocket,服务端也可能瞬时阻塞。我采用「分组投递 + 微间隔」:
- 每 10 只股票一组,每组发送后 sleep 0.1 秒。
- 每组内部股票以列表形式一次性订阅。
这样既保证了实时性,又让服务端处理得过来。
五、断了别慌,重连要有策略
WebSocket 也会因为网络切换或服务器维护断开。我设计的恢复逻辑包括:
- 心跳监测:定时 ping,检测连接是否存活。
- 指数退避:断线后第一次等 1 秒重连,失败则 2 秒、4 秒……最大 30 秒,防止在故障点反复撞墙。
- 局部重订阅:如果仅是某只股票数据异常,只对该股票发起重新订阅,不影响全局。
六、行情回来以后,处理要足够快
我让 on_message 只做一件事:把原始 tick 扔进 queue.Queue。另外启一个工作线程,从队列批量取出 100 条或间隔 0.2 秒,执行一次数据库批量写入。这样网络接收和处理完全异步,行情再密集也不会互相拖累。
七、动手试试
回顾整套方案:从链路上看,WebSocket 去掉了轮询重连;从策略上看,分批订阅、心跳退避提供了韧性;从实现上看,异步队列释放了本地算力。你把这三层叠加起来,港股实时行情抓取的超时问题自然就降低了。这套笔记你可以直接参考,动手改造自己的数据管道。
共同学习,写下你的评论
评论加载中...
作者其他优质文章
