你应该为异步对象使用“Using”吗?

时间:2013-01-07 02:41:53

标签: .net vb.net asynchronous

对异步对象使用Using块是否安全?如果在异步任务完成之前退出块,对象是否会过早处理?任务完成后会妥善处理吗?

这段代码有效,但我不知道它是否在滥用我的记忆。

For i = 1 To nPings
  Thread.Sleep(10)
  Using pPing As New System.Net.NetworkInformation.Ping
    AddHandler pPing.PingCompleted, AddressOf pingHandler
    pPing.SendAsync(ip, timeout)
  End Using
Next i

2 个答案:

答案 0 :(得分:3)

  
    

如果在异步任务完成之前退出该块,对象是否会过早处理?

  

是。只要End Using行完成,Ping对象就会被处理掉。

  
    

任务完成后是否会正确处理?

  

在您的示例中,Ping对象将始终被丢弃。但是,这可能会或可能不会在异步代码完成之后发生,因为该行为(您编码它的方式)尚未确定。

为了使此行为更具确定性,请在pingHandler代码中处理Ping对象,以便:

Class PingAsyncState

    Public Property Ping Ping
    Public Property int Timeout

End Class

For i = 1 To nPings
    Thread.Sleep(10)
    pPing As New System.Net.NetworkInformation.Ping
    AddHandler pPing.PingCompleted, AddressOf pingHandler
    pPing.SendAsync(ip, new PingAsyncState() With { .Ping = pPing, .Timeout = timeout })
Next i

Sub PingHandler(obj As Object)

    Dim state = CType(state, PingAsyncState)       

    ... code to do stuff ...

    state.Ping.Dispose()

End Sub

此外,如果您检查Ping.Dispose()内的代码,您会看到它关闭了各种EventHandles。如果在异步完成之前放置Ping对象,这可能不会导致异常,但它肯定会使Ping对象处于不稳定状态。您可能会发现事件未触发或异步完整处理程序代码未被调用或其他微妙的事情发生。

答案 1 :(得分:2)

我确信还有其他一些可以为您提供基本的.Net框架行为的详细解释,但结果是通过附加事件处理程序,即使在处理事件之后,该对象也会生效。

您可以通过以下修改来证明这一点:

    ' Add any initialization after the InitializeComponent() call.
    For i = 1 To 4
        System.Threading.Thread.Sleep(10)
        Using pPing As New System.Net.NetworkInformation.Ping
            AddHandler pPing.PingCompleted, AddressOf pingHandler
            AddHandler pPing.Disposed, AddressOf pingDisposed
            pPing.SendAsync("someaddressthatmayormaynotwork.com", 10000)
        End Using
    Next i
    GC.Collect()
    Console.WriteLine("completed")


Public Sub pingHandler(sender As Object, e As System.Net.NetworkInformation.PingCompletedEventArgs)
    Console.WriteLine("pingCompleted")
End Sub
Public Sub pingDisposed(sender As Object, e As System.EventArgs)
    Console.WriteLine("Disposed")
End Sub

在这种情况下,如果找到URL或接收响应花费的时间太长,则在触发pingHandler事件之前可以触发dispose事件,但pingHandler事件将始终触发。

通常,在事件中释放异步事件处理程序是最佳做法,这样您就不会遇到像这样的作用域/闭包场景:

Public Sub pingHandler(sender As Object, e As System.Net.NetworkInformation.PingCompletedEventArgs)
    If sender IsNot Nothing Then
        RemoveHandler DirectCast(sender, System.Net.NetworkInformation.Ping).PingCompleted, AddressOf pingHandler
    End If
    Console.WriteLine("pingCompleted")
End Sub

Public Sub pingDisposed(sender As Object, e As System.EventArgs)
    If sender IsNot Nothing Then
        RemoveHandler DirectCast(sender, System.Net.NetworkInformation.Ping).Disposed, AddressOf pingDisposed
    End If
    Console.WriteLine("Disposed")
End Sub