You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

NUMA架构Win10环境下多线程CPU密集型应用CPU利用率异常咨询

解决NUMA架构下多线程CPU密集型应用的低利用率问题

你遇到的这个情况是典型的NUMA(非统一内存访问)架构适配问题——你的程序在单NUMA节点的多核CPU(比如i7-6800K)上运行正常,但到了双路Xeon这种多NUMA节点的服务器上,因为没有针对NUMA做优化,线程和内存分配没有绑定到同一个节点,导致大量跨节点内存访问,而跨NUMA节点的内存延迟是同节点的2-3倍甚至更高,CPU大部分时间都在等待内存数据,直接拉低了整体利用率。

下面给你几个具体的解决步骤,亲测有效:

  • 第一步:先搞清楚服务器的NUMA布局
    Linux下直接跑numactl --hardware命令,就能看到每个NUMA节点的核心数、内存容量;Windows可以打开任务管理器,切换到“性能”标签,展开“CPU”就能看到NUMA节点的分布。比如你用的双Xeon E5-2660 v3,每个物理CPU对应一个NUMA节点,每个节点应该是10核20线程,总共有40线程,刚好匹配你的线程数。

  • 第二步:给线程绑定NUMA节点(设置亲和性)
    核心思路是让线程只在所属NUMA节点的核心上运行,避免跨节点调度:

    • Linux:可以用numactl命令快速验证,比如numactl --cpunodebind=0,1 --membind=0,1 ./your-application,这个命令会把进程的线程绑定到两个NUMA节点,同时内存也分配到对应节点。如果要更精细控制,比如把20个线程绑定到节点0,另外20个到节点1,可以在代码里用sched_setaffinity(C/C++)或者对应语言的亲和性API(比如Python的os.sched_setaffinity)来设置。
    • Windows:可以用SetThreadAffinityMask API在代码里给每个线程指定对应的NUMA节点核心,或者临时在任务管理器里右键你的进程→“设置相关性”,勾选对应NUMA节点的核心来测试效果。
  • 第三步:让内存分配和线程所在节点绑定
    很多默认的内存分配器(比如glibc的malloc)不会自动把内存分配到线程所在的NUMA节点,导致线程访问其他节点的内存,这才是利用率低的核心。解决方法:

    • Linux:可以用numactl --membind参数强制内存分配到指定节点,或者在代码里使用NUMA专用的分配函数,比如numa_alloc_local(需要链接libnuma库),确保线程使用的内存来自本地节点。
    • Windows:使用VirtualAllocExNuma API来指定内存分配的NUMA节点,替代默认的mallocnew
  • 第四步:调整线程分组策略
    既然你的服务器有两个NUMA节点,建议把40个线程分成两组,每组20个,分别绑定到两个节点,同时每组的内存都分配在对应的节点上。这样每个线程都访问本地节点的内存,避免跨节点的高延迟访问,CPU利用率会立刻上来。

  • 额外排查:排除锁竞争等其他瓶颈
    虽然大概率是NUMA问题,但也可以快速排查下是否有全局锁导致线程阻塞。Linux下用perf top或者perf record查看线程的等待状态,Windows用性能监视器查看线程的“等待时间百分比”,如果大部分线程在等待内存,那就是NUMA问题;如果是等待锁,那还要优化锁的粒度,比如用细粒度锁或者无锁数据结构。

内容的提问来源于stack exchange,提问作者Geom

火山引擎 最新活动