多线程场景下Interlocked.Increment隐式调用引发CPU开销问题排查
性能瓶颈排查:并发线程中隐式调用
System.Threading.Interlocked.Increment的问题 我在谷歌和Stack Overflow上未找到相关问题的解答,因此在此寻求帮助。
前言
我正在开发一款对性能要求极高的应用,采用多线程将任务分配至所有处理器核心以实现最大吞吐量。有意思的是,通过批量并行处理任务,原生方式能获得更高吞吐量。无论使用通用ThreadPool还是自定义线程池,均存在相同问题。我测试过Parallel(PLINQ)和Tasks,但它们会在堆上产生内存分配开销,我希望尽可能减少此类开销以降低GC压力。
问题详情
并发线程中的函数调用会隐式调用System.Threading.Interlocked.Increment方法,在递归函数中尤其会造成巨大开销。我对应用进行了性能分析,发现每个需要隐式保护其运行栈帧的函数调用都会调用该方法——推测是为确保局部变量的线程安全。这种互锁操作似乎由主线程管理,形成了严重的性能瓶颈。
- 性能分析截图1:标记行是该方法的内部调用位置,忽略底部的深红色线条,它们与函数的递归调用特性相关,数值过大正是由该问题导致。
- 性能分析截图2:我可以通过内联小型函数代码来减少该方法的隐式调用,但这对递归调用无效。
- 性能分析截图3:每次递归调用都会分支到该函数,给主线程带来明显开销。
线程初始化代码如下:
ThreadPool.UnsafeQueueUserWorkItem((l_state) => { action(l_state); //Other code omitted for brevity }, state);
性能分析所指向的调用函数如下:
public void ProcessCollisions(Collider collider) { var result = _tree.Query(in collider.Bounds); //Other code omitted for brevity }
补充说明:我在通用ThreadPool中排队的工作项数量多于处理器核心数,这是有意为之,目的是填补线程调度间隙,更高效地利用CPU核心。每个碰撞体对应一个ThreadPool工作项,由于ThreadPool线程是长生命周期的,最终会处理所有项,队列中可能存在数万个工作项。
已尝试的方案
- 使用自定义线程池替代通用ThreadPool:对所述问题无改善。
- 内联函数调用:仅为临时方案,非根本解决办法,且不适用于递归调用。
- 使用PLINQ:会产生内部堆内存分配,不符合需求。
- 使用Tasks:会产生内部堆内存分配,不符合需求。
核心疑问
关于线程执行,我是否忽略了什么关键点?是Query_Internal函数中对_tree内部数组的共享引用与使用导致的,还是存在某种与线程同步相关的隐式运行时处理?
内容的提问来源于stack exchange,提问作者Tim Otto
相关产品推荐
相关产品推荐

