¿CancelTokenSource.CancelAfter () tiene fugas?

El lanzamiento de laAsync Targeting Pack me instó a usarILSpy echar un vistazo a loPatrón asíncrono basado en tareas (TAP) allí se proporcionaron los métodos de extensión (algunos de los cuales ya he implementado por mi cuenta para su uso en VS2010). Me tropecé con el.CancelAfter(TimeSpan) método paraCancellationTokenSource (que es como un método de extensión en Async Targeting Pack para .NET 4.0 pero es un método de instancia en .NET 4.5) y pensó que podría ser una buena forma de implementar un tiempo de espera para varias operaciones que no tienen un tiempo de espera nativo, pero apoyan la cancelación.

Pero mirando la implementación en Async Targeting Pack, parece que si los asociadosTask Se completa o se cancela, el temporizador sigue funcionando.

/// <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);
}

Digamos que uso este método para proporcionar un tiempo de espera para una operación basada en TAP de uso frecuente, y lo envuelvo con un.CancelAfter(). Ahora digamos que el usuario proporciona un valor de tiempo de espera de 5 minutos (300 segundos) y llama a esta operación 100 veces por segundo, que se completa con éxito después de unos pocos milisegundos. Después de 300 segundos de 100 llamadas por segundo, se habrían acumulado 30,000 temporizadores de todas esas operaciones, a pesar de que las tareas se completaron con éxito hace mucho tiempo. Todos ellos eventualmente transcurrirán y ejecutarán el delegado anterior, que probablemente lanzará unObjectDisposedException, etc.

¿No es esto un comportamiento un tanto escurridizo y no escalable? Cuando implementé un timeout, utilicéTask/TaskEx.Delay(TimeSpan, CancellationToken) y cuando la tarea asociada ha finalizado, cancelo el.Delay() para que el temporizador se detenga y se elimine (es IDisposable después de todo, y contiene recursos no administrados). ¿Es esta limpieza demasiado celosa? ¿El costo de tener decenas de miles de temporizadores funcionando simultáneamente (y posiblemente lanzar decenas de miles de excepciones detectadas más tarde) realmente no tiene consecuencias para el rendimiento de la aplicación promedio? Es la sobrecarga y fugas de.CancelAfter() casi siempre minúsculo en comparación con el trabajo real que se está realizando, y en general, ¿se debe ignorar?

Respuestas a la pregunta(1)

Su respuesta a la pregunta