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

为什么C#中Task.Run搭配Task.WaitAll会出现线程阻塞问题

问题结论

该场景不属于死锁,是线程池饥饿,属于同步阻塞异步任务的典型异常表现,背后运行逻辑如下:

运行原理拆解

  1. 初始8个线程的来源
    .NET 线程池默认的最小工作线程数和CPU逻辑核心数一致,你日志里首次启动就有8个活跃工作线程,说明你的设备是8逻辑核,这是线程池默认的最小线程阈值,线程池会优先维持这个数量的线程可用。

  2. 任务阻塞的核心原因
    你通过Task.Run把100个任务全部投递到线程池工作队列,每个任务执行时都会调用Task.WaitAll同步阻塞当前线程,等待Task.Delay生成的任务完成。
    而Task.Delay的到期回调默认会投递到线程池的工作队列执行,此时所有可用的工作线程都被你投递的100个任务占满,全部处于阻塞状态,没有空闲线程处理Task.Delay的回调,因此t1、t2永远不会被标记为完成状态,Task.WaitAll就会一直阻塞不会返回。

  3. 线程每秒新增的逻辑
    当线程池检测到工作队列有排队任务、且当前所有工作线程都处于忙碌/阻塞状态时,会按照每秒1个的速度新增工作线程来消化队列任务。但你新增的线程一旦启动,就会执行到Task.WaitAll进入阻塞状态,还是没有多余线程处理Task.Delay的回调,最终就会出现线程数持续上涨但所有任务永远卡住的现象。

补充验证

你可以在代码开头添加ThreadPool.SetMinThreads(100, 100)修改线程池最小线程数,此时线程池会一次性初始化100个工作线程,处理完你投递的100个阻塞任务后还有剩余线程处理Task.Delay的回调,所有任务都会在5秒后正常执行结束。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 08:15:10