Async/Await 仍然阻塞 UI?
Posted
技术标签:
【中文标题】Async/Await 仍然阻塞 UI?【英文标题】:Async/Await is still blocking the UI? 【发布时间】:2019-11-22 03:03:54 【问题描述】:对 Async/Await 不是很熟悉,但是有这个 sn-p 的代码,并且在调用它时仍然会阻塞 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 线程)没有阻塞?
【问题讨论】:
不要使用.ConfigureAwait
UI 代码。
如果你将你的内部任务函数(使用Dim clientDone...
)移动到它自己的***函数,你的代码会更容易阅读。
您使用非异步套接字 API 有什么原因吗?
异步不创建线程。恰恰相反:它允许多个任务共享一个线程。如果它总是创建线程,那么我们就不需要发明 Async。我们只会使用线程。
【参考方案1】:
调用异步方法不会启动或使用不同的线程,也不会使该方法的执行异步执行。只有在该方法中第一次出现 await 操作时,才会将执行返回给调用者,并连接一个异步延续,以便稍后异步运行该方法的其余部分(有一个例外,但现在保持简单)。
但即使是这种延续也可能在调用线程上运行,尤其是在涉及同步上下文的情况下,例如在使用 WinForms 或 WPF 的情况下。它可能会导致死锁,但您已经通过添加 ConfigureAwait(false)
解决了它。
如果我理解正确(并且代码建议相同),您的代码中没有死锁,您只会在 UI 中体验“短暂”的无响应。我怀疑你稍后在Form_Load
函数中调用bTask.Result
,这会阻塞UI 线程直到IsPortReachable
完成其工作。将此阻止代码更改为 await bTask
应该可以解决您的问题。
旁注:我也会避免使用 ManualResetEvent 并使用 await 调用 socket.ConnectAsync()
。这种情况你也可以摆脱Task.Run(...)
。
【讨论】:
以上是关于Async/Await 仍然阻塞 UI?的主要内容,如果未能解决你的问题,请参考以下文章
Kotlin Coroutine,Android Async Task 和 Async await 的区别