Ist CancellationTokenSource.CancelAfter () undicht?

Die Veröffentlichung derAsync Targeting Pack veranlasste mich zu benutzenILSpy einen Blick auf was werfenAufgabenbasiertes asynchrones Muster (TAP) Dort wurden Erweiterungsmethoden bereitgestellt (von denen ich einige für VS2010 bereits selbst implementiert habe). Ich stolperte über die.CancelAfter(TimeSpan) Methode fürCancellationTokenSource (Dies ist eine Erweiterungsmethode im Async Targeting Pack für .NET 4.0, aber eine Instanzmethode in .NET 4.5.) Es ist eine gute Möglichkeit, eine Zeitüberschreitung für verschiedene Vorgänge zu implementieren, für die von Haus aus keine Zeitüberschreitung besteht. aber unterstütze die Kündigung.

Betrachtet man jedoch die Implementierung im Async Targeting Pack, so scheint es so, als ob das zugehörigeTask beendet oder abgebrochen wird, läuft der Timer weiter.

/// <summary>Cancels the <see cref="T:System.Threading.CancellationTokenSource" /> after the specified duration.</summary>
/// <param name="source">The CancellationTokenSource.</param>
/// <param name="dueTime">The due time in milliseconds for the source to be canceled.</param>
public static void CancelAfter(this CancellationTokenSource source, int dueTime)
{
    if (source == null)
    {
        throw new NullReferenceException();
    }
    if (dueTime < -1)
    {
        throw new ArgumentOutOfRangeException("dueTime");
    }
    Timer timer = new Timer(delegate(object self)
    {
        ((IDisposable)self).Dispose();
        try
        {
            source.Cancel();
        }
        catch (ObjectDisposedException)
        {
        }
    });
    timer.Change(dueTime, -1);
}

Angenommen, ich verwende diese Methode, um ein Timeout für einen häufig verwendeten TAP-basierten Vorgang bereitzustellen, und umhülle ihn mit einem.CancelAfter(). Nehmen wir nun an, der Benutzer gibt ein Zeitlimit von 5 Minuten (300 Sekunden) an und ruft diesen Vorgang 100 Mal pro Sekunde auf, die alle nach einigen Millisekunden erfolgreich abgeschlossen wurden. Nach 300 Sekunden von 100 Anrufen pro Sekunde hätten sich 30.000 laufende Timer aus all diesen Vorgängen angesammelt, obwohl die Aufgaben vor langer Zeit erfolgreich abgeschlossen wurden. Sie würden alle irgendwann ausfallen und den oben genannten Delegierten führen, der wahrscheinlich einen werfen wirdObjectDisposedException, usw.

Ist das nicht ein undichtes, nicht skalierbares Verhalten? Als ich ein Timeout implementiert habe, habe ich verwendetTask/TaskEx.Delay(TimeSpan, CancellationToken) und wenn die zugehörige Aufgabe beendet ist, brich ich die ab.Delay() damit der Timer gestoppt und entsorgt wird (es ist immerhin ein IDisposable und es enthält nicht verwaltete Ressourcen). Ist diese Bereinigung zu eifrig? Sind die Kosten für das gleichzeitige Ausführen von Zehntausenden von Timern (und möglicherweise das Auslösen von Zehntausenden von Ausnahmen) für die Leistung einer durchschnittlichen Anwendung wirklich unerheblich? Ist der Aufwand und die Undichtigkeit von.CancelAfter() fast immer winzig im Vergleich zu der tatsächlich geleisteten Arbeit, und sollte im Allgemeinen ignoriert werden?

Antworten auf die Frage(1)

Ihre Antwort auf die Frage