MetaTrader 5 中的并行计算:多核利用实测
一、MT5 并行计算的动机与限制
现代 PC 多核越来越多,但 MQL5 程序默认单线程跑,等于只用了 1 个核。处理器不会自动把“先输密码后验证”这类有依赖的逻辑拆开,必须由你标出“哪些部分可以并行”。MQL5 语言本身没有线程/并行运算符,要靠外部手段实现。
二、两条并行途径
- 途径 1:DLL。用带并行库的语言写 DLL,EA 调用即获得多线程能力。文章提及但未展开。
- 途径 2(重点):利用 MT5 非语言资源——把可并行代码拆成独立的指标或 EA,靠终端的多图表/多品种机制触发多核。
三、实测结论:跨品种才能用多核
文章用任务管理器观测核心占用,关键规律是:同一交易品种的所有指标跑在同一线程;不同品种的指标/EA 跑在不同线程。所以——同图表 2 指标=1 核,不同货币对不同图表 2 指标=2 核,不同图表 2 个 EA=2 核。最方便的组合是:EA(主模块)用 iCustom 在不同货币对上自动建计算指标(CM),由终端分配多核。
四、分发与收集:用全局变量
主模块(MM)在 OnInit 按 Threads 循环,用 iCustom 在不同货币对创建 CM 指标,每个分配不同的历史段偏移(BarStart);OnTick 里填当前模式并 SetParam 发“开始计算”信号。CM 指标在 OnInit 里用 while(true) 死循环等 Query→计算→把结果写回全局变量(如 MultiThread_<Magic>_0_Prognoze)。MM 轮询等 Answer 再读取,选最佳 rating。
五、性能实测
环境 EURUSD M1,模式长度 1440 柱,历史搜索 375000 柱:单线程(Threads=1)耗时 52 秒;并行(Threads=2,EA+2 个跨货币对 CM 指标)耗时 27 秒,加速比约 1.9 倍,接近线性。两种模式找到的历史相似图形日期极接近,证明正确性一致。
六、注意事项
七、最小可运行骨架
下面是文章“EA 主模块 + 跨货币对指标”方案的核心骨架:MM 在 OnInit 用 iCustom 在不同货币对创建计算指标(CM),用全局变量传参、CM 算完写回结果,MM 轮询读取:
// 主模块 OnInit:为每个线程在不同货币对建计算指标
string syms[2]={ "EURUSD", "GBPUSD" }; // 必须与 MM 不同品种
for(int t=0;t<Threads;t++)
iCustom(syms[t], _Period, "i-Thread", Prefix, t, _Symbol, Len, Len+t*Part, Part);
// 主模块 OnTick:发任务、等结果
SetParam(t, "Query");
while(!ParamExists(t,"Answer")) Sleep(100);
double progn = GetParam(t, "Prognoze"); // 取 CM 算回的结果
// 计算指标 i-Thread 的 OnInit 内:无限循环等 Query->算->写回
while(true)
{ Sleep(100); if(ParamExists(t,"Query")) { DeleteParam(t,"Query"); FindPrognoze(); SetParam(t,"Answer",1); } }
八、什么时候值得上并行
九、两种并行路线
MT5 并行计算有两条路:一是工作线程(Worker Thread),在主 EA 外起独立线程跑耗时任务,不阻塞 OnTick;二是 OpenCL,把海量并行计算(如大规模参数扫描、矩阵运算)丢给 GPU 或多核,速度数量级提升。
选哪条看任务形态:串行依赖强的逻辑用线程池分包,规整的 Numerical 计算用 OpenCL。两者都能把「单机跑几小时」压到「几分钟」。
十、用线程池扫参数
参数扫描天然可并行:把参数空间切成若干块,每个工作线程认领一块独立回测,结果汇总。这样 8 核机器接近 8 倍提速,且单线程崩了不影响其他块。
for(int i=worker_id; i<total; i+=num_workers) results[i] = Backtest(params[i]); // 每个线程跑自己那块
十一、线程安全与数据共享
多线程最大的坑是共享数据竞争:多个线程同时写同一个数组或变量会互相覆盖、结果错乱甚至崩溃。必须用临界区(CriticalSection)或把数据按线程分片(每人写自己的槽)来避免。
另一个坑是线程里不能调用某些终端 API(如交易函数),只能在主线程下单。并行层的职责要严格限定在「计算」,结果回主线程再执行。