2

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
4

2 に答える 2

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不安定な状態になります。イベントが発生しない、非同期完全ハンドラーコードが呼び出されない、またはその他の微妙なことが起こっている場合があります。

于 2013-01-07T03:16:52.077 に答える
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
于 2013-01-07T03:12:59.800 に答える