.NET async / await事件debouncer / throttler

问题描述 投票:0回答:1

我想通过async/await设想一个事件限制器(也称为去抖动器)在.NET中会出现什么问题。

请考虑以下代码。

/// <summary>
/// A local, in-memory event throttler/debuouncer.
/// </summary>
public class EventThrottler
{
    private TimeSpan _delay = TimeSpan.FromSeconds(5);

    /// <summary>
    /// Begin a timer to release callers of "AwaitEvent".
    /// If a timer has already begun, push it back for the length of 5 seconds.
    /// This method should not block.
    /// </summary>
    public void TriggerEvent()
    {
    }

    /// <summary>
    /// Multiple people can await.
    /// Callers will be released exactly 5 seconds after the last call to "TriggerEvent".
    /// If no call is ever made to "TriggerEvent", consumers of "AwaitEvent" will wait, indefinitely (or until CancellationToken is triggered).
    /// </summary>
    /// <param name="token"></param>
    /// <returns></returns>
    public Task AwaitEvent(CancellationToken token)
    {
        return Task.CompletedTask;
    }
}

我应该在这里使用什么方法?

所有来自ManualResetEvent的来电者都可以等待的AwaitEvent?然后,System.Timers.Timer在每次调用TriggerEvent后重置,最终会释放事件?

.net async-await throttling debouncing
1个回答
0
投票

我找到了解决方案。

public class EventThrottler
{
    private object _lock = new object();
    private CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
    private Timer _timer;

    public EventThrottler(TimeSpan delay)
    {
        _timer = new Timer();
        _timer.Interval = delay.TotalMilliseconds;
        _timer.AutoReset = false;
        _timer.Elapsed += OnTimerElapsed;
    }

    public void TriggerEvent()
    {
        _timer.Stop();
        _timer.Start();
    }

    public async Task AwaitEvent(CancellationToken token)
    {
        CancellationTokenSource tokenSource;

        lock (_lock)
        {
            if (_cancellationTokenSource == null)
            {
                _cancellationTokenSource = new CancellationTokenSource();
            }

            tokenSource = CancellationTokenSource.CreateLinkedTokenSource(token, _cancellationTokenSource.Token);
        }

        try
        {
            await Task.Delay(Timeout.Infinite, tokenSource.Token);
        }
        catch (TaskCanceledException ex)
        {
            if (token.IsCancellationRequested)
            {
                throw;
            }
        }
    }

    private void OnTimerElapsed(object sender, ElapsedEventArgs e)
    {
        CancellationTokenSource tokenSource = null;

        lock (_lock)
        {
            if (_cancellationTokenSource != null)
            {
                tokenSource = _cancellationTokenSource;
                _cancellationTokenSource = null;
            }
        }

        if (tokenSource != null)
        {
            tokenSource.Cancel();
            tokenSource.Dispose();
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.