Mac M1下C程序多线程读大文件:线程越多执行时间越长的原因
针对你在Mac M1上遇到的多线程读取大文件性能不升反降的问题,结合M1的硬件特性和你的实现方式,以下是几个核心原因:
磁盘IO饱和与调度开销
Mac M1搭载的NVMe磁盘虽性能强劲,但单盘的连续读写带宽、随机IOPS存在上限。当线程数超过2-3个时,多线程并行读取本质是争抢同一份磁盘资源,磁盘无法提供更高吞吐量,反而因线程上下文切换开销(内核切换线程栈、寄存器等操作)不断增加,抵消甚至超过多线程的潜在收益,最终拉长整体执行时间。M1的CPU核心调度特性
M1采用8核设计(4个高性能Firestorm核心 + 4个低功耗Icestorm核心)。线程数在2-3个时,系统可将线程分配到空闲大核,几乎无上下文切换,性能与单线程持平;但线程数超过8后,必然出现线程跨核心频繁切换,甚至唤醒更多低功耗核心调度,核心切换开销随线程数增加呈指数级上升,直接拖慢整体速度。MAP_PRIVATE映射的额外开销
你为每个线程创建独立的MAP_PRIVATE+PROT_READ映射,只读场景虽不会触发写时复制,但内核仍需为每个映射维护独立页表项、映射元数据。线程数越多,内核维护的映射结构越多,这部分内核态开销会被放大,成为性能瓶颈。全局单一映射因共享页表,这部分开销更小,但低线程数时不明显,线程数上来后才会凸显。缓存命中率下降与伪共享
单线程读取大文件时,CPU的L1/L2缓存可充分利用空间局部性,命中率很高;多线程同时读取不同文件区域时,访问地址分散,缓存无法复用,命中率急剧下降,需频繁从主存加载数据,增加延迟。另外,若每个线程的动态子数组内存地址相邻,可能触发缓存行伪共享——多个线程修改同一缓存行的不同位置,导致缓存频繁失效刷新,进一步降低性能。统一内存架构的带宽瓶颈
M1采用统一内存架构(UMA),CPU和GPU共享物理内存及带宽。多线程同时读取数GB级数据时,内存带宽会迅速被占满,后续线程需等待带宽资源,导致读取速度无法提升,甚至因等待队列变长而变慢。单线程或少量线程时,内存带宽未饱和,性能差异不大。
内容的提问来源于stack exchange,提问作者user25020188

