3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
stop(ContextInfo) 函数详解在 QMT(Quantitative Trader)量化交易平台中,编写复杂的量化策略时,我们经常会用到 Python 的多线程(threading)、网络套接字(socket)或数据库连接(如 sqlite3、pymongo)来处理异步任务或外部数据。然而,当策略被用户手动停止、重新编译或因异常退出时,如果这些外部资源没有被正确释放,就会导致内存泄漏、线程僵死、端口占用或数据库锁死等严重问题。
为了解决这一痛点,QMT 提供了 stop(ContextInfo) 生命周期回调函数。
stop(ContextInfo) 函数的作用stop(ContextInfo) 是 QMT 策略模型在关闭、停止运行前由 C++ 底层框架自动调用的清理函数。stop 函数,执行完毕后再正式销毁策略上下文。在 Python 中,直接强制杀死一个线程(如使用未公开的底层 API)是非常危险的,容易导致死锁或数据损坏。推荐的优雅做法是使用信号量(如 threading.Event)进行协同式退出。
init 中初始化一个 threading.Event() 退出标记,并启动子线程。is_set())。stop 函数中,将退出标记设为 True(调用 set()),并使用 join() 等待子线程安全结束。以下是一个完整的 QMT 策略模板,展示了如何利用 stop 函数在策略关闭时优雅地停止一个后台数据监控线程:
#encoding:gbk
import threading
import time
# 定义一个后台监控线程任务
def background_monitor(context_info, stop_event):
print("[子线程] 后台监控线程已启动...")
while not stop_event.is_set():
# 模拟每隔2秒获取一次外部数据或处理异步任务
print("[子线程] 正在监控盘口异常数据...")
# 使用小步长等待,以便能快速响应退出信号
for _ in range(20):
if stop_event.is_set():
break
time.sleep(0.1)
print("[子线程] 收到退出信号,子线程安全结束。")
def init(ContextInfo):
print("[主线程] 策略初始化开始...")
# 1. 创建线程退出事件信号
ContextInfo.stop_event = threading.Event()
# 2. 创建并启动子线程
ContextInfo.monitor_thread = threading.Thread(
target=background_monitor,
args=(ContextInfo, ContextInfo.stop_event)
)
# 设置为守护线程(可选,但建议配合 join 使用)
ContextInfo.monitor_thread.daemon = True
ContextInfo.monitor_thread.start()
print("[主线程] 子线程启动成功。")
def handlebar(ContextInfo):
# 策略核心逻辑
pass
def stop(ContextInfo):
"""
策略关闭前运行的清理函数
"""
print("[主线程] 触发 stop 回调,正在准备释放资源...")
# 1. 设置退出标记,通知子线程退出
if hasattr(ContextInfo, 'stop_event'):
ContextInfo.stop_event.set()
print("[主线程] 已向子线程发送退出信号。")
# 2. 等待子线程彻底结束,避免孤儿线程
if hasattr(ContextInfo, 'monitor_thread'):
print("[主线程] 正在等待子线程 join...")
ContextInfo.monitor_thread.join(timeout=5.0) # 设置超时时间防止主线程卡死
if ContextInfo.monitor_thread.is_alive():
print("[主线程] 警告:子线程未能在规定时间内退出!")
else:
print("[主线程] 子线程已成功回收。")
print("[主线程] 策略资源释放完毕,策略安全退出。")
stop 中执行耗时过长的操作:QMT 客户端在关闭策略时留给 stop 函数的响应时间是有限的。如果 stop 函数中存在死锁或超过数秒未返回,可能会导致客户端界面卡顿或强制终止该进程。join(timeout) 防止卡死:在回收线程时,务必为 join() 方法设置 timeout 参数(如 5.0 秒)。即使子线程由于某种原因发生死锁,主线程也能在超时后继续退出,防止整个 QMT 软件无响应。hasattr):在 stop 函数中访问 ContextInfo 上的自定义属性时,建议使用 hasattr(ContextInfo, 'xxx') 进行判断。因为如果策略在 init 阶段就发生异常崩溃,部分属性可能根本没有被成功创建。