VB.NET中的GUI延迟

时间:2014-11-26 08:45:17

标签: .net vb.net lag serial-communication mscomm32

我有一个执行串行通信的程序。发送命令后,程序必须等待一会儿才能接收数据。使用ActiveX MsComm

接收数据

http://msdn.microsoft.com/en-us/library/aa259393%28v=vs.60%29.aspx

psuedocode看起来像这样:

timer_tick

发送数据(节点1)

sleep(500)'同时接收节点1的数据

发送数据(节点2)

。 。

问题是睡眠导致GUI滞后。我想到了一些替代方案

1)在发送下一个命令之前使用定时器中的人工计数器大约500ms但对我来说似乎不是一个好主意 2)使用线程而不是计时器?并将其设置为后台线程

http://msdn.microsoft.com/en-us/library/system.threading.thread.isbackground(v=vs.71).aspx

3)使用application.doevents?

我对选项2或3不太熟悉,因此我犹豫是否可能将复杂的元素引入我的代码中。任何人都可以建议任何更适合这个问题的替代方案,或者开始朝着选项2或3方向努力吗?

2 个答案:

答案 0 :(得分:3)

问题在于您的timer正在UI线程上运行,因此当您在该子例程中sleep时,您正在睡眠UI线程(因此“滞后”)。

best 可能最容易理解的选项是向表单添加BackgroundWorker控件并将发送(和休眠)代码移动到worker DoWork例程中,不会阻止UI线程。

这样的事情:

Worker_DoWork
    send data (node 1)
    sleep(500) 'receives data for node 1 meanwhile
    send data (node 2)
End Sub

使用DoEvents 强烈不鼓励 - 在.NET中使用它的原因很少

答案 1 :(得分:2)

出现此问题是因为您正在将UI线程置于休眠状态。在.NET 4.5中,您可以使用Task.Delay使代码仅在一定间隔后执行而不阻塞任何线程,例如:

Dim port As New SerialPort
...
Public Async Sub SomeButton_Click()
    port.WriteLine("First")
    Await Task.Delay(500)
    port.WriteLine("Second")
    Await Task.Delay(300)
    port.WriteLine("Third")
End Sub

在这种情况下,第一个WriteLine在UI线程上执行,等待在后台发生500ms(实际上使用计时器),然后执行在原始线程(UI线程)和第二个{ {1}}也出现在UI线程中。另外300毫秒等待,然后第三个WriteLine也出现在UI线程中。

WriteLine组合允许您以非常干净的方式编写此类代码,而不涉及其他组件,如BackgroundWorker。它还允许您执行Background Worker无法执行的操作,例如执行多个异步调用。在这种情况下,您需要使用多个工作人员,现在您只需再写一个语句

请注意,Async\Await语法仅用于事件处理程序。在所有其他情况下,您应该使用Async Sub

如果要在后台线程中运行整个序列,可以使用Async Function SomeFunction() As Task

Task.Run

使用Tasks的真正之处在于,您可以组合多个异步操作,这几乎是BackgroundWorker无法实现的。在这种情况下,您可以异步读取文件或数据库中的数据,并使用非常简单的代码异步发送到串行端口:

Public Async Sub SomeButton_Click()
    Task.Run(Async Function () 
            Await SendAndWait
        End Function)
End Sub

public Async Function SendAndWait As Task
    _port.WriteLine("First")
    Await Task.Delay(500)
    _port.WriteLine("Second")
    Await Task.Delay(300)
    _port.WriteLine("Third")
End Function

您可以在.NET 4.0代码中使用public Async Function SendAndWait(filePath As String) As Task Dim line As String Using reader As New StreamReader(filePath) For i=0 To 3 line=Await reader.ReadLineAsync() _port.WriteLine(line) Await Task.Delay(500) Next End Using End Function 关键字,并将Microsoft.Bcl.Async包添加到项目中。