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

.NET 6+环境下F#计算进程心跳缓慢与卡顿问题求助

问题:计算密集型F# .NET进程出现Kestrel心跳超时警告及卡顿

我有一个运行计算密集型算法的F# .NET进程,因组合特性计算量可达数十亿次。为缩短执行时间,使用Async.Parallel(最大并行度为核心数)|> Async.RunSynchronously实现并行计算。进程可正常终止且结果正确,但日志中多次出现如下警告:

As of "07/26/2023 22:36:09 +00:00", the heartbeat has been running for "00:04:34.0765437" which is longer than "00:00:01". This could be caused by thread pool starvation. # {"EventId": {"Id": 22, "Name": "HeartbeatSlow"}, "SourceContext": "Microsoft.AspNetCore.Server.Kestrel"}

出现该警告时,进程会卡顿数秒至10分钟不等,之后恢复运行。请问该问题的原因是什么,如何解决?


原因分析

  • 线程池饥饿:Async.Parallel默认使用.NET线程池线程执行异步任务。当你用等于核心数的并行度跑计算密集型任务时,这些线程会被长时间占用(计算任务无IO等待,不会主动让出线程),导致线程池没有空闲线程处理Kestrel心跳检测、请求调度等关键后台任务。Kestrel心跳线程无法及时执行,触发超时警告,同时进程因线程池资源被占满出现卡顿。
  • 同步阻塞主线程:Async.RunSynchronously会阻塞调用线程(如果是ASP.NET Core请求线程,问题更严重),进一步加剧线程池资源紧张,导致后台任务排队等待时间过长。

解决方案

  • 用专用线程执行计算任务:
    • 创建计算任务时指定TaskCreationOptions.LongRunning,让.NET为计算任务分配非线程池的专用线程,避免占用线程池资源。F#中可通过async { ... } |> Async.StartAsTask(TaskCreationOptions.LongRunning)实现,或直接使用Task.Factory.StartNew(..., TaskCreationOptions.LongRunning)。
  • 调整线程池最小线程数:
    • 在程序启动时通过ThreadPool.SetMinThreads增加线程池最小工作线程数,让线程池能快速补充新线程处理后台任务。示例:ThreadPool.SetMinThreads(Environment.ProcessorCount * 2, Environment.ProcessorCount * 2)(可根据实际情况调整数值)。
  • 避免阻塞请求线程:
    • 如果是在ASP.NET Core环境中执行计算任务,不要用Async.RunSynchronously阻塞请求线程,改用await Async.StartAsTask()异步等待,让请求线程及时返回线程池供其他任务使用。
  • 拆分大计算任务:
    • 将数十亿次的计算拆分为更小批次,每个批次执行完成后插入短暂的Async.Sleep(1)或Task.Delay(1),主动让出线程给线程池后台任务,避免长时间占用线程资源。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 19:14:56