进程数超过核心数一半时性能下降的原因探究
关于多进程性能基准测试的现象解释
首先先把你的测试代码整理如下(格式化后):
# Date : 09/May/2018 # Platform : Linux import os import sys import ctypes import signal import multiprocessing as mp ncpu = 4 counter = 0 child_index = 0 process_list = [] shared_array = None def HandleSignal(signum, frame) : total = 0 print("Parent timeout hence terminate child") [hProc.terminate() for hProc in process_list] [hProc.join() for hProc in process_list] for each_count in shared_array : total += each_count print("{:,}".format(total)) def ChildHandleSignal(signum, frame) : # print("{} - {} : {:,}".format(child_index, os.getpid(), counter)) shared_array[child_index] = counter sys.exit(0) def entry_point(index, sarr) : global counter global child_index global shared_array child_index = index shared_array = sarr signal.signal(signal.SIGTERM, ChildHandleSignal) while True : counter += 1 return ncpu = int(sys.argv[1]) maxcpu = os.cpu_count() if ncpu > maxcpu : print("Number of CPU greater than maximum CPU") print("Setting number of CPU to maximum") ncpu = maxcpu shared_array = mp.Array(ctypes.c_int64, range(ncpu)) signal.signal(signal.SIGALRM, HandleSignal) signal.alarm(5) for I in range(ncpu) : p1 = mp.Process(target=entry_point, args=(I, shared_array, )) process_list.append(p1) p1.start() # I tried both with and with-out the below statement. The outputs are much similar os.sched_setaffinity(p1.pid, {I})
你观察到的“进程数达到核心数一半前性能持续上升,超过后下降”的现象,核心原因和Intel处理器的超线程技术以及CPU密集型任务的资源特性密切相关,咱们具体拆解:
1. 超线程的资源共享本质
你的两台测试机器:
- 谷歌云8VCPU虚拟机:底层实际是4个物理Intel核心,开启了超线程(每个物理核心模拟2个逻辑核心,也就是你看到的VCPU),所以“核心数一半”刚好是物理核心的数量。
- 48核物理机:应该是24个物理核心+超线程配置,“核心数一半”对应24个物理核心。
Intel的超线程技术是让一个物理核心同时运行两个逻辑线程,但这两个线程共享物理核心的绝大多数执行资源(比如算术逻辑单元ALU、浮点运算单元FPU、L1/L2缓存)。当你的进程数不超过物理核心数时,每个进程能独占一个物理核心的全部资源,CPU的计算能力被充分利用,性能随进程数线性上升;但当进程数超过物理核心数,开始使用超线程的逻辑核心时,两个进程会争抢同一个物理核心的有限资源,导致每个进程的执行效率下降,整体性能自然开始下滑。
2. 缓存命中率与内存带宽瓶颈
你的测试任务是纯CPU密集型的无限累加,非常依赖CPU缓存(L1/L2/L3)的命中率。当进程数超过物理核心数后:
- 多个进程共享同一个物理核心的缓存,缓存的有效容量被“拆分”,导致缓存命中率大幅下降;
- 缓存未命中时,进程需要频繁访问内存,而内存的读写速度远低于CPU缓存,这会带来显著的性能损耗;
- 同时,过多的进程会争抢内存带宽,进一步加剧性能下降。
3. 调度与上下文切换开销增加
虽然你用sched_setaffinity把进程绑定到了特定核心,但当进程数超过物理核心数后,操作系统依然需要在共享同一物理核心的两个逻辑线程之间进行调度。每次上下文切换都需要保存和恢复进程的寄存器、栈状态等,这些额外的开销会占用CPU资源,导致实际用于计算累加的时间减少,整体性能被拖累。
总结来说,你的测试结果完美体现了超线程技术在CPU密集型任务中的特性:物理核心是真正的性能瓶颈,超线程只能在部分场景(比如IO密集型任务)提升效率,对于纯计算的任务,超过物理核心数后反而会因为资源竞争导致性能下降。
内容的提问来源于stack exchange,提问作者Dinesh
相关产品推荐
相关产品推荐

