You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

双路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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 20:01:05