问题描述
各位大佬好,我想问一下,有的定时函数计算的比较慢,可能要30秒,早盘模拟交易时因为服务器负载大,可能计算的更慢,以至于超过1分钟。
假如我设置了
run_daily(funcA,'9:35')
run_daily(funcB,'9:36')
有可能因为计算速度慢,导致funcA没执行完就运行funcB吗?需要为funcA的运行预留几分钟的时间间隔吗?
解决方案
核心解答
在 JoinQuant(聚宽)量化平台中,所有的策略代码(包括 run_daily、run_weekly、run_monthly 等定时函数以及 handle_data)都是严格串行(单线程)执行的。
因此,不会出现 funcA 没执行完就开始运行 funcB 的情况。你不需要为了防止它们“并行冲突”而刻意预留时间间隔。
详细机制解析
1. 串行执行逻辑
聚宽的策略引擎在底层是单线程运行的(出于安全和资源隔离的考虑,平台禁用了多进程/多线程模式)。当你在策略中设定了多个定时任务时,引擎会维护一个时间事件队列:
- 到了
9:35,引擎触发并开始执行funcA。 - 假设
funcA计算非常复杂,耗时了 2 分钟(即真实时间到了9:37才执行完毕)。 - 引擎在执行完
funcA后,检查事件队列,发现9:36的funcB已经错过了触发时间,于是会立即开始执行funcB。
结论:funcB 会被阻塞,直到 funcA 完全执行结束才会启动。它们绝对不会同时运行,也不会导致变量读写冲突。
2. 潜在的风险与影响
虽然不用担心并行冲突,但长耗时的函数依然会带来其他负面影响,需要引起注意:
- 交易滑点与延迟:如果
funcA耗时过长,导致funcB延迟到9:37才执行,那么funcB中生成的交易信号和订单也会延迟发出。在早盘波动剧烈的时间段,这可能会导致严重的滑点。 - 超时强制终止:聚宽平台对单个函数的运行时间有严格限制。官方文档指出:每个函数运行时间不能超过 1800 秒(30分钟)。如果
funcA极端卡顿超过 30 分钟,整个策略进程会被系统强制杀死(抛出TimeoutError)。 - Tick 级别数据丢失:如果你同时订阅了 Tick 数据(
handle_tick),在funcA阻塞的这 1 分钟内,引擎无法处理新的 Tick 事件,可能会导致这期间的 Tick 逻辑被跳过。
3. 优化建议
为了避免早盘服务器负载大导致的严重延迟,建议采取以下优化措施:
- 提前计算:如果
funcA主要是进行数据准备、选股、复杂指标计算,且不需要用到9:30 - 9:35的盘中数据,强烈建议将其移到盘前执行(例如使用before_trading_start或run_daily(funcA, '09:00'))。 - 代码性能优化:
- 尽量使用 Pandas/Numpy 的向量化运算,避免使用
for循环遍历 DataFrame。 - 避免在循环中频繁调用
get_price、history等数据 API,应该一次性批量获取所需数据。 - 开启性能分析工具
enable_profile(),找出代码中的耗时瓶颈进行针对性优化。
- 尽量使用 Pandas/Numpy 的向量化运算,避免使用
- 合理安排时间:如果
funcA和funcB都有下单逻辑,且对时间敏感,尽量精简这两个函数,或者将非紧急的计算逻辑延后到盘后(after_trading_end)处理。