对Async / Await不太熟悉,但是有此代码段,并且在调用UI时仍会阻塞UI?我只得到“等待”光标,无法移动窗口,等等。
Public Async Function IsPortReachable(ByVal strHost As String, Optional ByVal intPort As Integer = 80, Optional ByVal intTimeoutMs As Integer = 5000) As Task(Of Boolean)
' Throw an exception if no host was passed
If String.IsNullOrEmpty(strHost) Then Throw New ArgumentNullException(NameOf(strHost))
Return Await Task.Run(Function()
Dim clientDone As ManualResetEvent = New ManualResetEvent(False)
Dim bReachable As Boolean = False
Dim hostEntry As DnsEndPoint = New DnsEndPoint(strHost, intPort)
Using socket = New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
Dim socketEventArg = New SocketAsyncEventArgs With {.RemoteEndPoint = hostEntry}
AddHandler socketEventArg.Completed, Sub(s, e)
bReachable = e.SocketError = SocketError.Success
clientDone.Set()
End Sub
clientDone.Reset()
socket.ConnectAsync(socketEventArg)
clientDone.WaitOne(intTimeoutMs)
Return bReachable
End Using
End Function).ConfigureAwait(False)
End Function
我从这样的主要形式调用它,它也发生在Form_Load
上,因此在用户能够“收回控制权”之前会有一个不必要的延迟:
Dim bTask As Task(Of Boolean) = IsPortReachable(dicValidated.Item("DNS2Up"), Convert.ToInt32(dicValidated.Item("DNS2UpPort")), 1000)
给我的印象是Async / Await函数在另一个线程上运行,而使调用线程(UI线程)不受阻塞?
答案 0 :(得分:0)
调用异步方法不会启动或使用其他线程,也不会使该方法的执行异步。仅在该方法中第一次发生await操作时,才会将执行返回给调用者,并连接异步继续以稍后异步地运行该方法的其余部分(有一个例外,但现在请使其保持简单)。 / p>
但是,即使继续执行也可以在调用线程上运行,尤其是在涉及到同步上下文的情况下,例如在使用WinForms或WPF的情况下。它可能导致死锁,但是您已经通过添加ConfigureAwait(false)
解决了它。
如果我理解正确(并且代码表明相同),则代码中没有死锁,您只会在UI中遇到“短暂的”无响应。我怀疑您稍后在bTask.Result
函数中调用Form_Load
,这会阻塞UI线程,直到IsPortReachable
完成其工作。将此阻止代码更改为await bTask
应该可以解决您的问题。
旁注:我还将避免使用ManualResetEvent并使用await来调用socket.ConnectAsync()
。这种情况下,您也可以摆脱Task.Run(...)
。