请参阅以下代码,我已从以下网页进行了改编:http://www.codeguru.com/csharp/csharp/introduction-to-async-and-await-keywords-in-c-5.0.htm
Public Class Form1
Private Async Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
Dim program As New Program()
Await program.PrintSumAsync()
MsgBox("got here 1")
End Sub
End Class
Class Program
Public Async Function PrintSumAsync() As Task
Dim value1 As Integer = Await GetValueAsync()
Dim value2 As Integer = Await GetValueAsync()
Console.WriteLine("Sum of two random numbers is: {0}", value1 + value2)
End Function
Private Async Function GetValueAsync() As Task(Of Integer)
System.Threading.Thread.Sleep(5000)
Dim random As Integer = ComputeValue()
Return random
End Function
Private Function ComputeValue() As Integer
MsgBox("got here 2")
Return New Random().[Next](1, 1000)
End Function
End Class
我在GetValueAsync中添加了对Sleep的调用,因此需要一段时间才能完成。
我希望代码在msgbox2之前到达msgbox1(在这里得到1)(到这里2)。等待似乎停止了主线程。我错过了什么?我对newish await关键字没有任何经验。我最近从.net 3.5升级到.NET 4.5.2。
更新 根据戴维斯的回答,我编写了如下代码:
Public Class Form1
Private Async Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
test()
MsgBox("got here 1")
End Sub
Public Async Sub test()
Dim program As New Program()
Await program.PrintSumAsync()
'Dim task As Task = program.PrintSumAsync()
MsgBox("got here 2")
End Sub
End Class
Class Program
Public Async Function PrintSumAsync() As Task
Dim value1 As Integer = Await GetValueAsync()
Dim value2 As Integer = Await GetValueAsync()
Console.WriteLine("Sum of two random numbers is: {0}", value1 + value2)
End Function
Private Async Function GetValueAsync() As Task(Of Integer)
Try
Await Task.Delay(5000)
Dim random As Integer = ComputeValue()
Return random
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Function
Private Function ComputeValue() As Integer
MsgBox("got here 2")
Return New Random().[Next](1, 1000)
End Function
End Class
如何在消息框2出现之前停止主线程完成?
答案 0 :(得分:4)
Await
没有停止主线程,你是:
System.Threading.Thread.Sleep(5000)
此方法中没有发生异步:
Private Async Function GetValueAsync() As Task(Of Integer)
System.Threading.Thread.Sleep(5000)
Dim random As Integer = ComputeValue()
Return random
End Function
(我很惊讶编译器没有抱怨它。它与C#有关。)因此,即使方法签名和使用代码都使用Async
和Await
关键字进行修饰,代码实际上并不是异步的。但是,如果等待该方法中的异步操作,可以。例如:
Private Async Function GetValueAsync() As Task(Of Integer)
Await Task.Delay(5000)
Dim random As Integer = ComputeValue()
Return random
End Function
这将使整个操作堆栈异步,充分利用新关键字。
但请注意,观察到的结果可能仍然相同。看看顶级方法:
Private Async Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
Dim program As New Program()
Await program.PrintSumAsync()
MsgBox("got here 1")
End Sub
在等待第二行直到完成之后,该方法中的代码仍然不会执行第三行。 非常顶级(调用此处理程序的UI)将继续而不等待此方法,但此方法将等待其异步操作完成后再继续。
为了获得您正在寻找的结果,您需要捕获Task
而不是等待它。像这样:
Private Async Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
Dim program As New Program()
Dim task As Task = program.PrintSumAsync()
MsgBox("got here 1")
' do something with the task object.
' await it, provide it with a callback function for when it completes, etc.
End Sub
Async
和Await
关键字不一定会在新线程上发生函数。对于大多数意图和目的,您通常可以将它们视为简单的句法简写,用于在ContinueWith()
Task
对象上包装方法的一部分。在任何给定的Async
方法中,都需要Await
来放置ContinueWith()
。如果其中没有Await
,则Async
方法不是异步的。
答案 1 :(得分:1)
只是因为粗暴和胫骨,玩这个。在我看来,获取随机值的过程应该在 parallel :
中运行Public Class Form1
Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Button1.Enabled = False
Label1.Text = DateTime.Now
Label2.Text = ""
Await test()
Label2.Text = DateTime.Now
Button1.Enabled = True
End Sub
Public Async Function test() As Task
Dim program As New Program()
Await Task.Run(New Action(AddressOf program.PrintSum))
End Function
End Class
Class Program
Private R As New Random
Public Sub PrintSum()
' get some random values IN PARALLEL and wait for them all to finish
Dim tasks As New List(Of Task(Of Integer))
For i As Integer = 1 To 5
tasks.Add(Task(Of Integer).Factory.StartNew(Function() GetValue()))
Next
Task.WaitAll(tasks.ToArray)
Dim sum As Integer = 0
For i As Integer = 0 To tasks.Count - 1
sum = sum + tasks(i).Result
Next
Console.WriteLine("Sum of the random numbers is: " & sum)
End Sub
Private Function GetValue() As Integer
Console.WriteLine("Getting value...")
System.Threading.Thread.Sleep(R.Next(3000, 10001)) ' random 3 to 10 second delay
Return ComputeValue()
End Function
Private Function ComputeValue() As Integer
Dim i As Integer = R.Next(1, 1000)
Console.WriteLine("Value selected: " & i)
Return i
End Function
End Class