首先,我不是问C# - Alternative to Thread.Sleep?或Alternative to Thread.Sleep in C#?相同的问题。我认为我没有错误地使用它,并且需要在特定情况下使用真正的替代方案。
在代码分析运行期间,我看到了一个令人惊讶的违规行为:
Thread.Sleep()的使用是设计缺陷的标志。
此违规导致Peter Richie's article导致为什么这会构成糟糕的设计。
我们都知道线程创建很昂贵,线程中的阻塞意味着池上的争用。我们也知道每个线程将分配一个兆内存,因此它应该有一个短的寿命,在UI上阻塞是邪恶的,使用睡眠时间是不可靠的等等。这导致我的观点,如果你真的需要执行睡觉,如果不是Thread.Sleep,你应该使用什么?
Peter继续提到零睡眠是Thread.Sleep的唯一正确用法,有效地放弃了线程的时间片并允许其他线程处理。然后更可怕的是,这仅仅是因为非托管线程的限制,如果在CLR中重新实现将产生在应用程序中使用Thread.Sleep的副作用。事实上,常见的不良用法的所有要点都是不良用法的好例子。
我在使用Thread.Sleep的生产代码中遇到以下情况:
在这种情况下不使用Thread.Sleep,我还有其他选择吗?紧密的循环往往会使事情变得更糟,我不相信这会使它的使用成为“设计缺陷”,尤其是因为UI上没有任何东西,只有后台线程。在多线程环境中等待其他事情的软件本质就是影响代码的外部因素,有时你需要等待......
答案 0 :(得分:11)
WaitHandle
类型和派生类型提供了一种事件驱动机制,用于等待与操作系统的连接。例如,当您有Task<T> task
并且通过访问task.Result
等待结果时,内部实现不会轮询Thread.Sleep
之间的调用。它使用WaitHandle
派生类型来进行等待和同步。
有时,基于轮询的方法是必要的,就像您在项目符号列表中提供的一些示例一样,但通常可以使用事件驱动的方法。并不是Thread.Sleep
总是 不好 - 只是经常被滥用。
在多线程环境中等待其他事情的软件本质就是影响代码的外部因素,有时你需要等待......
等待 很好。 等待投票 通常不是(*)。如果您有任何方法可以使用 事件驱动的等待 ,您通常应该努力使用它。
我对你正在询问的具体内容并不十分了解,所以我不会详细说明。如果你发表评论,我可以扩大我的答案。
(*) 等待投票 的理论原因不好如下:
假设我的代码如下所示:
//START
Begin();
while (!Done())
Thread.Sleep(D);
//STOP
Begin()
开始一些操作。 Done()
返回true
表示操作已完成。假设这将在大约T
时间后发生。然后:
Done()
)T/D
次START
到STOP
的持续时间包含预期的D/2
,纯粹是因为Thread.Sleep
您应该选择D
的价值?当您增加D
时,START
到STOP
的预期持续时间会线性增加。当您减少D
时,(绑定)迭代次数将增加为1/D
。这两个都很糟糕,找到正确的D
是有问题的。
现在将其与 事件驱动的等待 进行比较:
//START
Begin();
WaitDone();
//STOP
从理论上讲,只要WaitDone()
以某种方式神奇地等待操作完成但不再等待, 在轮询中等待的两个问题 案例已经消失:这个帖子等待了恰当的时间 - 不多也不少!
重申我开始的观点:在.NET中,WaitHandle
类和派生类型是促进这种方法的原因。
答案 1 :(得分:2)
嗯,你说的大部分都是。引用“我们都知道线程创建是昂贵的,并且线程中的阻塞意味着池上的争用”,因此您甚至可以理解使用线程池的内容。
您也明白阻止UI线程是不好的。
再次查看线程池模型:您有一个线程池,可能每个处理器一个,然后将任务传递给它们。它会阻止其中一个线程有什么意义?如果现在没有工作要做,那么它应该只是进行一项不同的任务。
所以,直接回答你的问题“如果你真的需要进行睡眠,那么你应该使用什么,如果不是Thread.Sleep?”,在现代精心设计的程序中,你永远不会需要这样做,你只需为后者安排任务。
您应该将池中的线程(与系统中的处理器一样)视为资源,在不需要时应将其释放给其他人。
回到你的例子,你有点过分参与命令式编程范式。
等待同步机制并不“糟糕”。
答案 2 :(得分:-1)
在我的一个项目中,我使用了2个线程,我遇到了问题,将UI冻结thnx到Thread.Sleep ....这解决了我的问题:
public static void Sleeping(int miliseconds)
{
var task = Sleep(miliseconds);
task.Wait();
}
public static async Task Sleep(int miliseconds)
{
await Task.Delay(miliseconds);
}