代码之家  ›  专栏  ›  技术社区  ›  Paul Knopf

.NET异步/等待事件取消公告器/节流器

  •  0
  • Paul Knopf  · 技术社区  · 6 年前

    我很难想象在.NET中,使用 async/await .

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

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

    A. ManualResetEvent AwaitEvent 你能等吗?然后,一个 System.Timers.Timer 在每次调用 TriggerEvent ,最终将发布该事件?

    0 回复  |  直到 6 年前
        1
  •  0
  •   Paul Knopf    6 年前

    我找到了解决办法。

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