0

我有一个用于执行串行通信的程序。发送命令后,程序需要等待一小段时间才能接收到数据。使用 ActiveX MsComm 接收数据

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

伪代码如下所示:

timer_tick

发送数据(节点 1)

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

发送数据(节点 2)

. . .

问题是睡眠会导致 GUI 滞后。我想了几个替代方案

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

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

3)利用application.doevents?

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

4

2 回答 2

3

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

最好的可能最容易理解的选项是向BackgroundWorker您的表单添加一个控件并将您的发送(和睡眠)代码移动到工作DoWork程序中,这不会阻塞 UI 线程。

像这样的东西:

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

强烈建议不要使用- 在 .NET 中使用DoEvents它的理由很少

于 2014-11-26T09:26:19.600 回答
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 线程上执行,在后台等待 500 毫秒(实际上使用计时器),然后在原始线程(UI 线程)上恢复执行,第二次WriteLine也在 UI 线程中发生。再等待 300 毫秒,然后第三个 WriteLine 也出现在 UI 线程中。

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

请注意,该Async Sub语法仅用于事件处理程序。在所有其他情况下,您应该使用Async Function SomeFunction() As Task.

如果要在后台线程中运行整个序列,可以使用Task.Run.

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

使用 Tasks 的真正美妙之处在于,您可以组合多个异步操作,这在 BackgroundWorker 中几乎是不可能的。在这种情况下,您可以从文件或数据库中异步读取数据,然后将其异步发送到串口,代码非常简单:

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包添加到您的项目中来使用async/await.NET 4.0 代码中的关键字。

于 2014-11-26T09:57:21.770 回答