对异步对象使用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
答案 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