双路Windows机器上如何让PPL的parallel_for利用全部NUMA节点?
解决PPL parallel_for无法利用全部NUMA节点的问题
1. 显式配置NUMA感知的调度器策略
PPL默认调度器可能不会自动跨NUMA节点分配负载,你可以通过SchedulerPolicy强制调度器使用所有可用的执行资源:
#include <concrt.h> #include <ppl.h> int main() { // 创建调度器策略,设置最小/最大并发数为系统最大执行资源数 concurrency::SchedulerPolicy policy(2, concurrency::MinConcurrency, concurrency::MaxExecutionResources, concurrency::MaxConcurrency, concurrency::MaxExecutionResources); // 将该策略设为默认调度器 concurrency::Scheduler::SetDefaultSchedulerPolicy(policy); // 执行并行任务 concurrency::parallel_for(0, 100000000, [](int i) { // 替换为你的计算逻辑 volatile double x = sqrt(i); }); return 0; }
2. 调整进程亲和性掩码
如果进程被限制在单个NUMA节点的核心上,可通过Windows API解除限制,让进程访问所有逻辑核心:
#include <windows.h> #include <concrt.h> #include <ppl.h> int main() { DWORD_PTR processAffinity = 0; DWORD_PTR systemAffinity = 0; GetProcessAffinityMask(GetCurrentProcess(), &processAffinity, &systemAffinity); // 设置进程亲和性为系统所有可用核心 SetProcessAffinityMask(GetCurrentProcess(), systemAffinity); concurrency::parallel_for(0, 100000000, [](int i) { volatile double x = sqrt(i); }); return 0; }
3. 手动拆分任务到各NUMA节点
若上述方法无效,可针对每个NUMA节点创建独立调度器,拆分任务并行执行:
#include <concrt.h> #include <ppl.h> #include <vector> int main() { const int numaNodeCount = concurrency::GetProcessorNodeCount(); std::vector<concurrency::Scheduler*> schedulers(numaNodeCount); // 为每个NUMA节点创建专属调度器 for (int i = 0; i < numaNodeCount; ++i) { concurrency::SchedulerPolicy policy(1, concurrency::ProcessorNode, i); schedulers[i] = concurrency::Scheduler::Create(policy); schedulers[i]->Attach(); } // 拆分任务到各个节点执行 concurrency::parallel_for(0, numaNodeCount, [&](int nodeIdx) { const int taskRange = 100000000 / numaNodeCount; int start = nodeIdx * taskRange; int end = (nodeIdx == numaNodeCount - 1) ? 100000000 : (nodeIdx + 1) * taskRange; concurrency::parallel_for(start, end, [](int i) { volatile double x = sqrt(i); }); }); // 清理调度器资源 for (auto scheduler : schedulers) { scheduler->Detach(); scheduler->Release(); } return 0; }
4. 验证任务分布情况
可以在任务中打印当前线程所在的NUMA节点,确认负载是否分布到所有节点:
concurrency::parallel_for(0, 100, [](int i) { int nodeId = concurrency::GetProcessorNodeId(concurrency::GetCurrentThreadId()); printf("任务%d运行在NUMA节点%d\n", i, nodeId); });
内容的提问来源于stack exchange,提问作者yusk
相关产品推荐
相关产品推荐

