我想通过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
后重置,最终会释放事件?
我找到了解决方案。
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();
}
}
}