我正在将同步代码转换为异步代码。我在VB.net中有一个Windows窗体应用程序,它显示了物理设备的表示,这些设备是由邮局管理员管理的注册邮件的一部分。
因此PostManager类用于操作RegistrationPost对象。这些注册信息包含多个设备,这些设备需要以某种方式与Socket通信连接。这些设备通过实现“连接”子/功能符合IDevice接口。
下面是代码的精简版本,以了解我正在尝试做什么:
Private Sub Form_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Try
...
Dim pm As New PostManager
pm.ConnectAndStartPosts
...
Catch ex As Exception
...
End Try
End Sub
然后在PostManager类中:
Friend Sub ConnectAndStartPosts()
' The global variable "Posts" is a List of RegistrationPost objects
Parallel.ForEach(Of RegistrationPost)(Posts, Sub(x) x.ConnectAndStartReading())
End Sub
然后在RegistrationPost类中:
Public Sub ConnectAndStartReading()
Parallel.ForEach(Of IDevice)(AllDevices, Sub(x)
x.Connect()
...
End Sub)
End Sub
然后在IDevice里面:
Public Sub Connect() Implements IDevice.Connect
' socket is a global variable of the type Socket(SocketType.Stream, ProtocolType.Tcp)
socket.Connect(IP, Port)
... more code gets executed (if connected, log a message)
NotifyPropertyChanged("Connected")
End Sub
好的,这一切都正常,但我当然希望使用async / await来获得异步连接外部套接字的所有好处。但我无法理解“冒泡”async / await关键字的程度有多远?我害怕遇到性能问题,因为每次使用async / await关键字时,都会创建一个状态机,所以可能不需要一直使用它?
放弃Parallel.Foreach并去常规ForEach也会更好吗?甚至是另一种方法?请参阅下文,这将如何影响代码示例:
' Async/await here as well?
Private async Sub Form_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Try
...
Dim pm As New PostManager
await pm.ConnectAndStartPosts
...
Catch ex As Exception
...
End Try
End Sub
然后在PostManager类中:
' Leave this a regular 'Sub' or transform to async Function as Task?
Friend Sub ConnectAndStartPosts()
' The global variable "Posts" is a List of RegistrationPost objects
Parallel.ForEach(Of RegistrationPost)(Posts, async Sub(x) await x.ConnectAndStartReading())
End Sub
然后在RegistrationPost类中:
' Leave this a regular 'Sub' or transform to async Function as Task?
Public async Function ConnectAndStartReading() as Task
Parallel.ForEach(Of IDevice)(AllDevices, async Sub(x)
await x.Connect()
... more code, start reading, etc...
End Sub)
End Function
然后在IDevice里面:
Public async Function Connect() as Task Implements IDevice.Connect
' socket is a global variable of the type Socket(SocketType.Stream, ProtocolType.Tcp)
await socket.ConnectAsync(IP, Port)
... more code gets executed (if connected, log a message)
NotifyPropertyChanged("Connected")
End Function
我无法理解“冒泡”async / await关键字的程度有多远?我害怕遇到性能问题,因为每次使用async / await关键字时,都会创建一个状态机,所以可能不需要一直使用它?
你应该去async
all the way。 async
/ await
的开销,而not zero,一旦你有真正的I / O继续,就会在噪音中完全丢失。
放弃Parallel.Foreach并去常规ForEach也会更好吗?甚至是另一种方法?
是。 Parallel
用于CPU绑定代码。对于异步并发,请使用Task.WhenAll
。即,为每个设备调用新的ConnectAsync
方法(例如,使用LINQ的Select
),然后对生成的任务执行Await Task.WhenAll
。您可以为注册帖子做同样的事情。
我更改了代码以反映所选答案中的建议。我不确定我是否应该提出新问题,但我现在在这里:
但是这需要异步完成注册邮件的集合。我不知道如何获得一个注册信息集合来同步连接和开始阅读,同时异步运行任务本身。
所以在第3步中,我正在寻找一种方法:await Task.WhenAll(collectionOfTasks),其中每个单独的任务在任务中等待两个。