使用Thread.Sleep等待的替代方法 [英] Alternatives to using Thread.Sleep for waiting

查看:896
本文介绍了使用Thread.Sleep等待的替代方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先,我没有问与> C#-Thread.Sleep的替代品相同的问题? 替代C#中的Thread.Sleep?.我认为我没有错误地使用它,在某些情况下需要真正的替代品.

Firstly I am not asking the same question as C# - Alternative to Thread.Sleep?, or Alternative to Thread.Sleep in C#?. I don't think I am using it incorrectly and need a genuine alternative for specific situations.

在运行代码分析期间,我看到了令人惊讶的违规行为:

During a code analysis run I saw a surprising violation coming up:

使用Thread.Sleep()表示设计存在缺陷.

Usage of Thread.Sleep() is a sign of flawed design.

此违规行为导致

This violation leads to Peter Richie's article on why exactly this constitutes bad design.

我们都知道线程创建是昂贵的,线程阻塞意味着池中的争用.我们也知道每个线程都会分配一个内存,因此它的寿命应该很短,UI上的阻塞是邪恶的,使用sleep进行计时是不可靠的,等等,等等.这导致了我的意思,如果您确实需要执行睡觉,如果不是Thread.Sleep,应该使用什么?

We all know thread creation is expensive and blocking in threads means contention on the pool. We also know that each thread will allocate a meg of memory so it should have a short lifespan, blocking on the UI is evil, using sleep for timing is unreliable etc etc etc. Which leads me to my point, if you really need to perform a sleep, what should you be using if not Thread.Sleep?

Peter继续提到零睡眠是Thread.Sleep的唯一正确用法,它有效地放弃了线程的时间片并允许其他线程进行处理.然后更令人恐惧的是,这仅是由于非托管线程的限制所致,如果在CLR中重新实现,则会在应用程序中使用Thread.Sleep产生副作用.实际上,有关常见不良用法的所有要点都是不良用法的很好例子.

Peter goes on to mention that a zero sleep is the only correct use of Thread.Sleep effectively giving up the thread's timeslice and allowing other threads to process. And then even more scary is that this is only a because of limitations on unmanaged threads and if re-implemented in the CLR will create side effects of using Thread.Sleep in your applications. All the points on common bad usage are, in fact, good examples of bad usage.

在生产代码中,我非常成功地使用Thread.Sleep时遇到以下情况:

I have the following situations in production code that uses Thread.Sleep quite successfully:

  • 等待操作系统放弃文件锁(捕获文件锁问题,等待一秒钟,重试,过一会儿放弃).
  • 杀死一个进程并等待它不显示在进程列表中(杀死它,检查它是否未运行,等待一秒钟,检查它是否仍未运行,强制将其关闭).
  • 等待复制缓冲区刷新(检查文件大小,尝试访问它,等待,检查大小是否已更改).
  • Waiting for a file lock to be relinquished by the operating system (catch file lock problems, wait for a second, try again, give up after a while).
  • Killing a process and waiting for it not to show up in the process list (kill it, check it's not running, wait for a second, check it not still running, force it closed).
  • Waiting for copy buffers to flush (check a file size, try to access it, wait, check if size has changed).

在这种情况下不使用Thread.Sleep,我还有哪些其他选择?紧密的循环会使情况变得更糟,我不认为这会使它的用法成为设计缺陷",特别是因为UI上没有任何内容,而仅在后台线程中.在多线程环境中等待其他因素的影响只是软件的本性,外部因素会影响您的代码,有时您需要等待...

Without using Thread.Sleep in situations like these, what other options do I have? Tight loops tend to make things worse and I don't believe this makes it's usage a "design flaw" especially since nothing is on the UI and only in background threads. It is just the nature of software to wait for other things in a multi-threaded environment with external factors affecting your code, sometimes you need to wait...

推荐答案

The WaitHandle type and derived types provide an event-driven mechanism for waiting that ties into the operating system. For example, when you have a Task<T> task and you wait on the result by accessing task.Result, the internal implementation isn't polling with Thread.Sleep calls in between. It's using a WaitHandle-derived type to do waiting and synchronization.

有时,像在项目符号列表中提供的一些示例中一样,基于轮询的方法是必需的,但通常可以使用事件驱动的方法来代替.并不是Thread.Sleep总是 不好-只是经常被滥用.

Sometimes a polling-based approach is necessary, as in some of the examples you gave in your bullet list, but often you can use an event-driven approach instead. It's not that Thread.Sleep is always bad - it's just that it is very often misused.

在多线程环境中等待其他事情,而外部因素会影响您的代码,这只是软件的本性,有时您需要等待...

It is just the nature of software to wait for other things in a multi-threaded environment with external factors affecting your code, sometimes you need to wait...

等待 可以. 等待轮询 通常不是(*).如果有任何方法可以使用 事件驱动的等待方式 ,则通常应努力使用它.

To wait is fine. To wait with polling is often not (*). If there is any way you can use an event-driven wait, you should typically strive to use that.

对于您要问的确切内容,我感觉不太好,因此我不会在此赘述.如果您有任何评论,我可以扩大答案.

I don't have a very good feel for exactly what it is that you're asking, so I won't elaborate beyond this. If you leave a comment I can expand my answer.

(*) 等待轮询 的理论原因如下:

(*) The theoretical reason waiting with polling is bad is as follows:

假设我有如下代码:

//START
Begin();
while (!Done())
    Thread.Sleep(D);
//STOP

Begin()开始一些操作. Done()返回true表示操作已完成.假设这将在大约T时间后发生.然后:

Begin() starts some operation. Done() returning true means the operation has finished. Suppose this will happen after approximately T time. Then:

  • 线程唤醒并检查条件(调用Done())T/D
  • STARTSTOP的持续时间包括预期的D/2纯粹是因为Thread.Sleep
  • The thread wakes up and checks the condition (calls Done()) T/D times
  • The duration from START to STOP includes an expected D/2 purely because of the Thread.Sleep

您应该选择D的哪个值?随着增加D,预期持续时间形式从STARTSTOP线性增加.随着您减小D,迭代次数(的上界)将随着1/D的增加而增加.这两个都是不好的,找到正确的D是有问题的.

What value of D should you choose? As you increase D, the expected duration form START to STOP increases linearly. As you decrease D, the (bound on the) number of iterations increases as 1/D. Both of these are bad, and finding the right D is problematic.

现在将其与 事件驱动的等待 进行比较:

Now compare this to an event-driven wait:

//START
Begin();
WaitDone();
//STOP

从理论上讲,只要WaitDone()以某种方式神奇地等待直到操作完成,但不再继续,在 等待轮询 案例中确定的两个问题都存在消失了:这个线程等待的时间恰到好处-不多,不多!

Theoretically speaking, as long as WaitDone() somehow magically waits until the operation has finished but no longer, both of the problems identified in the waiting with polling case have disappeared: this thread waits for exactly the right amount of time - no more, no less!

重申一下我的初衷:在.NET中,WaitHandle类和派生类型是实现此方法的便利.

To reiterate the point I started with: in .NET, the WaitHandle class and derived types are what facilitate this approach.

这篇关于使用Thread.Sleep等待的替代方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆