关于C#工作线程中Thread.Sleep与Task.Delay的执行差异问询
C# ThreadPool线程延迟执行问题分析
在测试代码中出现了两种差异明显的执行现象:
- 使用
await Task.Delay(5000);时,所有Console.WriteLine("START TestSemaPhoreSlims:ID[" + ids + "]...")语句无延迟执行; - 使用
Thread.Sleep(5000);时,从ID:7开始,日志输出出现逐秒延迟,与预期的立即执行不符。
测试代码
public class SemaPhoreTest1s { public SemaPhoreTest1s() { for (int i = 1; i <= 10; i++) { int idnums = i; Task.Run(() => TestSemaPhoreSlims("ID:" + idnums)); } Console.WriteLine("MAIN THREAD:" + Thread.CurrentThread.ManagedThreadId); Console.ReadLine(); } public async void TestSemaPhoreSlims(string ids) { int workerThreads, completionPortThreads; ThreadPool.GetAvailableThreads(out workerThreads, out completionPortThreads); Console.WriteLine("START TestSemaPhoreSlims:ID[" + ids + "] workerThreads>>>" + workerThreads + ": times>>>" + DateTime.Now.ToString("HH-mm-ss")); Thread.Sleep(5000); //await Task.Delay(5000); } }
执行日志
MAIN THREAD:1 START TestSemaPhoreSlims:ID[ID:2] workerThreads>>>2041: times>>>16-06-43 START TestSemaPhoreSlims:ID[ID:1] workerThreads>>>2041: times>>>16-06-43 START TestSemaPhoreSlims:ID[ID:5] workerThreads>>>2041: times>>>16-06-43 START TestSemaPhoreSlims:ID[ID:4] workerThreads>>>2041: times>>>16-06-43 START TestSemaPhoreSlims:ID[ID:3] workerThreads>>>2041: times>>>16-06-43 START TestSemaPhoreSlims:ID[ID:6] workerThreads>>>2041: times>>>16-06-43 START TestSemaPhoreSlims:ID[ID:7] workerThreads>>>2040: times>>>16-06-44 START TestSemaPhoreSlims:ID[ID:8] workerThreads>>>2039: times>>>16-06-45 START TestSemaPhoreSlims:ID[ID:9] workerThreads>>>2038: times>>>16-06-46 START TestSemaPhoreSlims:ID[ID:10] workerThreads>>>2037: times>>>16-06-47
现象原因分析
ThreadPool的线程调度规则
ThreadPool默认维护的最小工作线程数通常等于CPU核心数(比如6核机器初始为6个)。当任务数量超过当前可用线程数时,ThreadPool不会立刻创建新线程,而是会等待1秒冷却时间,确认任务仍在排队后才会启动新线程。Thread.Sleep的阻塞特性
使用Thread.Sleep(5000)时,前6个任务会占用ThreadPool的初始6个工作线程,且这些线程会被Sleep完全阻塞,无法被其他任务复用。第7到第10个任务需要等待ThreadPool创建新线程,由于每次创建新线程有1秒延迟,因此这几个任务的日志输出会逐秒延后,出现ID:7到ID:10的时间依次加1秒的现象。await Task.Delay的非阻塞特性
使用await Task.Delay(5000)时,await关键字会在等待延迟的过程中释放当前占用的ThreadPool线程,让线程回到线程池供其他任务使用。后续任务可以立即获取空闲线程执行,因此所有Console.WriteLine语句都能无延迟输出。
内容的提问来源于stack exchange,提问作者licenniezh
相关产品推荐
相关产品推荐

