我有一个执行串行通信的程序。发送命令后,程序必须等待一会儿才能接收数据。使用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方向努力吗?
答案 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包添加到项目中。