【问题标题】:Alternative to Thread.Sleep that keeps the UI responsive?保持 UI 响应的 Thread.Sleep 的替代方案?
【发布时间】:2011-03-27 15:58:09
【问题描述】:

我在 Visual Studio 2008 中使用 C# 完成所有这些工作。

我想放慢我的算法的工作速度,以便用户可以观看它的工作。 GUI 上有一个可见的周期性变化,所以我在每个实例之后添加了Thread.Sleep

问题是Thread.Sleep,当设置为至少一秒时,在Thread.Sleep 的几个实例之后(经过几个循环)只会冻结整个 GUI 并保持这种状态直到程序完成。不是马上,但它总是会发生。多快取决于睡眠时间的长短。

我有证据表明整个程序没有冻结,它正在工作,甚至睡眠也在正确长度的暂停。但 GUI 会在某个点冻结,直到算法结束,此时它显示正确的最终状态。

如何解决这个问题?在特定点暂停算法的替代方案?

【问题讨论】:

  • 如果你贴出相关代码会更容易帮助到你。
  • 尝试挖掘多线程 Edmund
  • 没有任何相关的代码 sn-p 可以发布,除了整个代码。我只是在使用: Thread.Sleep(1000);当我想要暂停 1 秒时。
  • @Hogan DoEvents?嘘。嘶。但是,当有睡眠活动时没有多大用处。
  • just answered this question。您想改用Timer。不要使用DoEvents;这不是任何问题的正确答案。

标签: c# multithreading user-interface visual-studio-2008 thread-sleep


【解决方案1】:

首先,不要让用户在考虑何时完成之前就等待完成的工作。没有用。请说不。

其次,您正在“休眠” UI 线程。这就是 UI 线程“锁定”的原因。 UI线程不能被阻塞;如果是,则 UI 线程无法更新表单上的控件并响应系统消息。响应系统消息是UI线程的一项重要任务;不这样做会使您的应用程序看起来被系统锁定。不是什么好事。

如果您想完成此操作(请不要),只需在您开始工作时创建一个Timer,当它Ticks 时,表示该停止假装工作了。

再次,请不要这样做。

【讨论】:

  • 同意。如果您确实想让用户观看,至少要有一个油门,一旦他们厌倦了观看(在第一次之后),他们可以将速度恢复到正常水平。跨度>
【解决方案2】:

我猜一切都用完了一个线程。用户可能通过单击按钮或类似按钮来调用此算法。这由主线程的消息队列处理。在此事件处理程序返回之前,您的应用程序的 GUI 无法更新。它需要定期抽取消息队列以保持响应。

睡眠几乎从来都不是一个好主意,在 GUI 线程中也绝对不是一个好主意。我不建议您继续使用睡眠并通过调用 Application.DoEvents 使您的 GUI 响应。

相反,您应该在后台线程中运行此算法,并在完成时向主线程发出信号。

【讨论】:

  • 很好的答案——我说看看——你解释了。
  • @Hogan:我认为你误解了大卫的回答。他根本不建议您“调查”DoEvents。事实上,他建议您远离。这不是正确的答案;对于那些首先使用错误解决方案的人来说,这是一个肮脏的黑客行为。 DoEvents 在这里制造的问题比它的帮助要多。
  • @Hogan 答案没有重写。
  • @Cody -- 了解DoEvents() 的作用解释了为什么 OP 的程序不起作用。有了这些知识,重新设计就很清楚了。我支持需要了解 DoEvents() 和 Windows 消息泵的 OP。
  • @Hogan:你们的 cmets 都没有提到 Windows 消息泵。我会给那个+1。提到DoEvents 会皱眉。太多的程序员错误地使用它(通常,它根本就在使用它)。在我看来,它看起来很可疑,就像你在推荐它一样。我不是想在这里叫你出来。我只是注意到DoEvents 不是一个好的解决方案,即使它看起来像是快速修复。了解为什么会出现问题当然是最理想的选择,但根据我的经验,将人们引向正确的方向并不能完全让他们到达那里。
【解决方案3】:

您将提交一些相当常见的用户界面漏洞:

  • 不要用细节向用户发送垃圾邮件,她只对结果感兴趣
  • 不要强迫用户按照您的要求快速工作
  • 不要禁止用户在您忙碌时与您的程序进行交互。

改为:

  • 在 ListBox 之类的小工具中显示结果,以便用户按自己的节奏查看结果
  • 使用线程保持用户界面交互
  • 使用调试器为您自己的利益减慢时间

【讨论】:

  • 平心而论,我们不知道应用程序是什么。也许重点是实际看到算法工作(不太可能,但可能)。例如,请参阅boxcar2d.com,该应用程序的重点是观察遗传算法的“运行情况”。
【解决方案4】:

这取决于很多事情,因此很难从您所说的内容中给出具体的答案。不过,这里有一些可能相关的问题:

您是否在 UI 线程上执行此操作(例如,触发工作开始的表单按钮或 UI 事件的线程)?如果是这样,最好创建一个新线程来执行该工作。

你为什么要睡觉?如果与正在进行的工作相关的状态对所有相关线程都可用,那么观察者是否可以在工作线程不休眠的情况下观察到这一点?也许工作线程可以将当前进度的指示器写入 volatile 或锁定变量(如果它大于指针大小 - 例如 int 或对象 - 则必须锁定它 - 但不是其他情况。如果未锁定,那么 volatile 将阻止缓存CPU 之间的不一致,尽管这可能不是什么大问题)。在这种情况下,您可以有一个表单计时器(.Net 中有不同的计时器具有不同的用途)检查该变量的状态并更新 UI 以反映正在完成的工作,而工作线程不需要做任何事情。偶尔在工作线程中使用Yield() 最多可能是有益的,但即使这样也不太可能需要。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-13
    相关资源
    最近更新 更多