🗒️C#程序等待的几种方法解析
2023-12-26
| 2023-12-26
0  |  0 分钟
type
status
date
slug
summary
tags
category
icon
password
🧐
本篇文章将从源码的角度,对几种C#中常见的等待方法进行解析。

Thread.Sleep()

Thread.Yield()

主动放弃当前线程的时间片,使得操作系统调度其他就绪态的线程使用一个时间片。将当前线程放入就绪队列中,若无其他处于就绪态的线程,则当前线程继续运行。
可通过判断返回的Boolean值,判断是否成功调用了其他线程。可以让低于线程优先级的线程被调度,但仅限于同一处理器中的线程。

Thread.Sleep(0)

放弃当前线程剩余时间片,将当前线程置于就绪状态。
可以调度任何处理器的线程使用时间片。但只能让优先级相同或者更高的线程使用该时间片。当没有其他合适的线程时,将会导致CPU占用100%。

Thread.Sleep(1)

放弃当前线程剩余时间片, 并休息1毫秒(时间不精确,一般会滞后几毫秒或者一个时间片)。
可以调度任何处理器的线程使用时间片。所有优先级的线程都可以使用该时间片。因为会休息1毫秒,所以即使没有合适的线程,也不会占用较多的CPU资源。

SpinWait

SpinOnce()

初始10SpinOnce 将进行操作数递增的自旋。
10次以后,首先会使用Thread.Yield 让出当前时间片,但是在某些情况下,系统会考虑和当前线程在同一处理器处于就绪态的线程;
所以会使用Thread.Sleep(0) ,但是可能会导致只有低优先级线程时(低优先级线程得不到执行),当前线程一直处于自旋状态占用CPU;
最终也会混着执行Thread.Sleep(1) 来使得所有就绪态的线程都能得到执行,但是可能会导致当前线程被移除线程队列10ms以上。

SpinUntil

内部使用SpinOnce

Task.Delay

使用Timer ,在到达指定时间后,将Task 设定为Complete
使用Timer.KeepRootedWhileScheduled ,抑制终结器,防止timer被回收。
技术分享
  • 开发
  • .NET
  • ExecutionContext vs SynchronizationContextExecutionContext vs SynchronizationContext
    目录