.NET异步/等待事件去抖动器/抑制器

时间:2019-03-11 17:33:04

标签: .net async-await throttling debouncing

我很难想象使用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之后被重置,最终将释放事件吗?

1 个答案:

答案 0 :(得分: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();
        }
    }
}
相关问题