首页 > 解决方案 > .NET Async/Await - 何时返回任务和何时等待

问题描述

我正在将同步代码转换为异步代码。我在 VB.net 中有一个 Windows 窗体应用程序,它显示了物理设备的表示,这些物理设备是由 postmanager 管理的registrationpost 的一部分。

所以 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

标签: .netvb.netasynchronousasync-await

解决方案


我无法理解将 async/await 关键字“冒泡”多远?我害怕遇到性能问题,因为每次使用 async/await 关键字时,都会创建一个状态机,所以可能不需要一直向上?

你应该async一路走下去async/的开销await虽然不是零,但一旦您进行真正的 I/O,就会完全消失在噪音中。

放弃 Parallel.Foreach 并选择常规的 ForEach 会更好吗?甚至另一种方法?

是的。Parallel适用于受 CPU 限制的代码。对于异步并发,使用Task.WhenAll. 即,ConnectAsync为每个设备调用您的新方法(例如,使用 LINQ Select),然后Await Task.WhenAll对生成的任务执行一次。您可以对注册帖子执行相同的操作。


推荐阅读