关键问题是Async 不会神奇地使您的方法异步。它只让编译器知道您的方法将包含Await 关键字,并且代码需要为converted into a state machine。 任何未被等待的代码都会同步执行,即使方法被标记为Async。考虑以下示例:
Private Async Sub Form1_Load(sender As Object,
e As EventArgs) Handles MyBase.Load
Await LongRunning1() 'opens the form, then asynchronously changes
'Text property after 2 seconds
End Sub
Private Async Function LongRunning1() As Task
Await Task.Factory.StartNew(Sub() Threading.Thread.Sleep(2000))
Me.Text = "Finished LongRunning1"
End Function
这里一个长时间运行的进程,以Thread.Sleep为例,被包装到一个Task中,并且有一个Await关键字。它告诉编译器在执行下一行之前等待任务中的语句完成。如果没有Await,Text 属性将立即设置。
现在假设您的 Async 方法中有一些长时间运行的同步代码:
Private Async Sub Form1_Load(sender As Object,
e As EventArgs) Handles MyBase.Load
Await LongRunning2() 'synchronously waits 2 seconds, opens the form,
'then asynchronously changes Text property after 2 seconds
End Sub
Private Async Function LongRunning2() As Task
Threading.Thread.Sleep(2000)
Await LongRunning1()
Me.Text = "Finished LongRunning2"
End Function
请注意,在这种情况下,它会同步等待 Thread.Sleep 完成,因此对于最终用户,您的应用显示为挂起。底线是 - 你必须知道哪些方法调用可以长时间运行,并将它们包装到基于任务的等待模型中。否则你可能会看到你所看到的问题。
如果这听起来太复杂,您可以启动后台工作程序 (.NET 2.0+),或使用 TPL (.NET 4.0+) 启动任务。如果您希望进入较低级别,则从 .NET 1.1 开始可以使用线程。然后在表单/控件的顶部显示一些等待/进度窗口/覆盖,该功能尚不可用。看看这些:
感谢@PanagiotisKanavos 为我指明了正确的方向。