Bur*_*imi 117 c# multithreading sleep
我经常看到它提到Thread.Sleep();不应该使用,但我不明白为什么会这样.如果Thread.Sleep();可能造成麻烦,是否有任何替代解决方案具有相同的安全性?
例如.
while(true)
{
doSomework();
i++;
Thread.Sleep(5000);
}
Run Code Online (Sandbox Code Playgroud)
另一个是:
while (true)
{
string[] images = Directory.GetFiles(@"C:\Dir", "*.png");
foreach (string image in images)
{
this.Invoke(() => this.Enabled = true);
pictureBox1.Image = new Bitmap(image);
Thread.Sleep(1000);
}
}
Run Code Online (Sandbox Code Playgroud)
And*_*air 153
与通话的问题Thread.Sleep都相当简洁解释在这里:
Thread.Sleep有它的用途:在MTA线程上测试/调试时模拟冗长的操作.在.NET中,没有其他理由可以使用它.
Thread.Sleep(n)表示阻止当前线程至少在n毫秒内可能发生的次数(或线程量子).时间片的长度在不同版本/类型的Windows和不同处理器上是不同的,通常在15到30毫秒的范围内.这意味着线程几乎可以保证阻塞超过n毫秒.你的线程在n毫秒之后完全重新唤醒的可能性几乎是不可能的. 所以,Thread.Sleep时机毫无意义.线程是一种有限的资源,它们需要大约200,000个周期才能创建,大约100,000个周期需要销毁.默认情况下,它们为其堆栈保留1兆字节的虚拟内存,并为每个上下文切换使用2,000-8,000个周期.这使得任何等待线程都成为 巨大的浪费.
首选解决方案:WaitHandles
最糟糕的错误是使用Thread.Sleepwhile-construct(演示和答案,不错的博客条目)
编辑:
我想提高我的答案:
我们有两种不同的用例:
我们正在等待,因为我们知道一个特定的时间跨度时,我们应该继续(使用
Thread.Sleep,System.Threading.Timer或相似者)我们正在等待,因为某些条件会在一段时间内发生变化...关键字是一段时间了!如果条件检查在我们的代码域中,我们应该使用WaitHandles - 否则外部组件应该提供某种钩子......如果不是它的设计是坏的!
我的回答主要包括用例2
Swa*_*Jat 32
SCENARIO 1 - 等待异步任务完成:我同意WaitHandle/Auto | ManualResetEvent应该在线程正在等待另一个线程上的任务完成的场景中使用.
SCENARIO 2 - while while循环:然而,作为一个粗略的计时机制(同时+ Thread.Sleep)对于99%的应用程序是完全正常的,这些应用程序不需要确切地知道被阻止的线程何时应该"唤醒*.它需要的参数创建线程的200k周期也是无效的 - 无论如何都需要创建定时循环线程,200k周期只是另一个大数字(告诉我打开文件/套接字/ db调用多少个周期?).
因此,如果while + Thread.Sleep工作,为什么复杂的事情?只有语法律师才会实用!
我想从编码政治的角度来回答这个问题,这可能对任何人都有帮助,也可能没有帮助.但是,当您处理专为9-5企业程序员设计的工具时,编写文档的人倾向于使用"不应该"和"从不"这样的词来表示"不要这样做,除非你真的知道你是什么'做和为什么'.
我在C#世界中的另外几个最喜欢的是他们告诉你"永远不要叫锁(这个)"或"从不调用GC.Collect()".这两个在许多博客和官方文档中被强制声明,IMO是完全错误的信息.在某种程度上,这种错误信息是出于其目的,因为在完全研究替代方案之前,它使初学者远离做他们不理解的事情,但同时,它很难通过搜索引擎找到所有信息.似乎指向文章告诉你不要做什么,而不回答问题"为什么不呢?"
在政治上,它归结为人们认为"好的设计"或"糟糕的设计".官方文档不应该指示我的应用程序的设计.如果真的有技术原因你不应该调用sleep(),那么IMO文档应该说明在特定场景下调用它是完全可以的,但是可能提供一些与场景无关或更适合其他场景的替代解决方案.场景.
显然,调用"sleep()"在许多情况下很有用,因为在实际时间条件下明确定义了截止日期,但是,在开始抛出睡眠之前,有更多复杂的系统可供等待和发信号通知应该被考虑和理解(进入你的代码,并在你的代码中抛出不必要的sleep()语句通常被认为是初学者的策略.
这是人们警告的示例的 1).spinning 和 2).polling 循环,而不是 Thread.Sleep() 部分。我认为 Thread.Sleep() 通常被添加来轻松改进旋转或轮询循环中的代码,因此它仅与“坏”代码相关联。
此外,人们还会做以下事情:
while(inWait)Thread.Sleep(5000);
Run Code Online (Sandbox Code Playgroud)
其中变量 inWait 不是以线程安全的方式访问的,这也会导致问题。
程序员想要看到的是由 Events 和 Signaling and Locking 构造控制的线程,当你这样做时,你将不需要 Thread.Sleep(),并且也消除了对线程安全变量访问的担忧。例如,您能否创建一个与 FileSystemWatcher 类关联的事件处理程序,并使用一个事件来触发您的第二个示例而不是循环?
正如 Andreas N. 提到的,阅读Joe Albahari 所著的 C# 线程,它真的非常好。
小智 5
在以下情况下使用睡眠:您无法控制的独立程序有时可能使用常用资源(例如文件),您的程序在运行时需要访问该资源,以及当这些资源正在使用时其他程序您的程序被阻止使用它。在这种情况下,当您在代码中访问资源时,将对资源的访问放在 try-catch 中(以在无法访问资源时捕获异常),并将其放入 while 循环中。如果资源空闲,则永远不会调用 sleep。但是如果资源被阻塞,那么你会休眠一段适当的时间,并尝试再次访问资源(这就是你循环的原因)。但是,请记住,您必须在循环上放置某种限制器,因此它不是潜在的无限循环。
我有一个用例,我在这里没有完全看到,并且会认为这是使用 Thread.Sleep() 的正当理由:
在运行清理作业的控制台应用程序中,我需要对由数千个并发用户共享的数据库进行大量相当昂贵的数据库调用。为了不破坏数据库并排除其他数据库几个小时,我需要在调用之间暂停大约 100 毫秒。这与计时无关,只是为了让其他线程能够访问数据库。
在可能需要 500 毫秒执行的调用之间花费 2000-8000 个周期进行上下文切换是良性的,为线程提供 1 MB 堆栈也是如此,该线程作为服务器上的单个实例运行。
| 归档时间: |
|
| 查看次数: |
169608 次 |
| 最近记录: |