简单、非阻塞的休眠方式?

10

我在谷歌上搜索了一下,并阅读了一些相关帖子,但是我没有找到一种简单的方法可以让 VB.Net 应用程序暂停一小会儿并仍然保持应用程序的响应性:

Imports System.Net
Imports System.IO
Imports System.Text
Imports System.Text.RegularExpressions
Imports System.Threading.Thread

[...]

''#How to keep screen frop freezing?
While True
  ListBox1.Items.Clear()

  ListBox1.Items.Add("blah")

  ''#Not much difference
  ListBox1.Refresh()

  ''#Wait 1mn
  Sleep(60000)
End While

有没有简单的、非阻塞的解决方案可以让VB.Net应用程序等待几秒钟呢?

谢谢。


1
睡眠的目的是什么?你要么想让它休眠,要么想让它响应。如果你想做的是定期发生的事情,那就明确说明。 - dbasnett
我每分钟都在屏幕抓取一个网页,并希望应用程序每分钟暂停一次,而不会导致应用程序屏幕冻结。是否仍然可以使用DoEvents,还是建议改用Timer? - Gulbahar
谢谢大家,我会使用计时器。 - Gulbahar
@OverTheRainbow - 你使用计时器完成了你想要的工作吗? - Seth Moore
我尝试了这里提供的大部分方法。它们都给我带来了问题,除了计时器方法,它运行得非常好。 - Off The Gold
显示剩余3条评论
8个回答

8
Public Sub ResponsiveSleep(ByRef iMilliSeconds As Integer)
    Dim i As Integer, iHalfSeconds As Integer = iMilliSeconds / 500
    For i = 1 To iHalfSeconds
        Threading.Thread.Sleep(500) : Application.DoEvents()
    Next i
End Sub

调用 ResponsiveSleep 函数来暂停特定的代码,同时保持应用程序相对响应。为了使应用程序更加响应,可以将 iHalfSeconds 修改为十分之一或百分之一秒。


1
这种方法使用的 CPU 资源比 Stopwatch 更少。 - rsrobbins
2
我曾经遇到过Application.DoEvents()的问题。例如,请查看这里 - darda
这个 : 结构是VB特有的吗?在C#中会是什么样子? - Nyerguds

7

这是WinForms还是WPF?

如果是WinForms,您可以使用计时器而不是while循环。然后您的应用程序仍将响应并引发事件。

在WPF中,我认为您需要基于DispatchTimer类创建自己的计时器。


WPF 也有定时器吗? - CoderDennis
我刚刚快速打开了一个项目,在设计器中没有看到任何计时器控件,所以很可能是没有的,我在WPF中从来没有需要使用过它。在谷歌上快速搜索让我认为它不可用(http://social.msdn.microsoft.com/forums/en-US/wpf/thread/aaffea95-e735-492d-bd8a-2fdf7099a936/)。 - Seth Moore
它不一定要是控件,对吧?你可以在代码中使用System.Timers.Timer或System.Threading.Timer。 - Ravi Y

5
这段简单的代码怎么样 - :)
Private Async Sub Button10_Click(sender As Object, e As EventArgs) Handles Button10.Click
        MsgBox("This msgbox is shown immidiatly. click OK and hover mouse over other controls to see if UI is freezed")
        Await Task.Delay(5000)
        MsgBox("see? UI did'nt freez :). Notice the keyword 'Async' between Private and Sub")
    End Sub

在声明的子程序上使用Async,然后将Await Task.Delay(milliseconds)替换为Thread.Sleep(milliseconds)


为什么没有人知道这个?非常感谢! - John Kens

4
Private Sub wait(ByVal interval As Integer)
    Dim stopW As New Stopwatch
    stopW.Start()
    Do While stopW.ElapsedMilliseconds < interval
        ' Allows your UI to remain responsive
        Application.DoEvents()
    Loop
    stopW.Stop()
End Sub

3

实际上,解决方案有两个: 1.) 使用计时器而不是睡眠,睡眠会导致线程休眠。 2.) 使用多线程,并将屏幕抓取功能运行在自己的线程中,这将极大地提高应用程序的响应能力。

Threading.Thread.Sleep(IntSleepTime)

这是一个线程安全的休眠函数,可以暂停当前线程指定的时间。如果您要使用sleep函数,在多线程环境下也可以使用,它会使得应用程序的其他部分保持响应,因为您只会休眠一个分支线程,而不是主线程。


1

计时器建议确实是最好的方法。但如果DoEvents仍然有效(自从5.0以来我就没有使用VB了),你可以这样做:

For i = 0 To 600
    DoEvents
    Sleep(100)
Next

这将执行600个每次0.1秒的休眠,每个休眠之间都有一个DoEvents来处理当前事件。0.1秒应该是响应性(事件在0.1秒内被处理)和CPU消耗之间的一个很好的折衷方案(如果执行得太快,您的应用程序甚至在等待时也会消耗大量的CPU时间)。


亲爱的点踩者,虽然我尊重您的点踩,但您是否考虑留下评论,让我可以改进我的回答呢?谢谢。 - Wim
我也不知道为什么这个被踩了。在.NET中,这些函数被称为Application.DoEvents和Thread.Sleep,但是任何拥有最新MSDN的人都可以找到它们。应该指出,DoEvents可能会导致各种奇怪的行为(例如,如果在函数运行时关闭窗体或者如果DoEvents再次调用相同的函数)。但是你确实说过这不是理想的方法。 - Niki
1
我不是那个点踩者,但DoEvents并不是一个好的编程实践。如果方法没有正确编写以考虑重新进入,则会导致问题。 - Joel Coehoorn

0

这是针对VB而不是VBA的。

    Private Async Function PauseTime(ByVal MS As Integer) As Task

    Await Task.Run(Sub()                         
                           Thread.Sleep(MS)

                   End Sub)


     End Function

0

你正在使用UI线程来使窗体休眠。如果你想让你的应用程序响应更快,首先要创建一个方法来添加列表视图中的项目,当你的窗体加载时,使用线程启动该方法,现在使用sleep来使你的列表视图线程休眠,这样你的窗体就可以保持响应状态了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接