【发布时间】:2021-07-28 00:19:15
【问题描述】:
我正在尝试了解节流和去抖动的工作原理,因为我现在在我的应用程序中需要它们。
I have found this article here that explains it pretty well
据我了解,
Throttling 限制了在确定的时间内可以调用函数的次数。例如,只允许 xFunction 每 5 秒触发一次。
自上次调用以来经过给定时间后,去抖动会触发 xFunction。例如,如果用户单击鼠标 1000 次,xFunction 将在最后一次调用后 5 秒触发。
为了更好地理解节流以及如何从上面链接的文章中提供的类,我创建了一个控制台应用程序,如果用户在其中按下任何键,控制台应用程序将显示该键。
我现在正在尝试限制显示键的次数,但我的代码似乎无法正常工作。每当我按下一个键时,都会显示我按下的键但是hello() 永远不会运行。
这是我所拥有的:
class Program
{
static void Main(string[] args)
{
DebounceDispatcher debounceDispatcher = new DebounceDispatcher();
ConsoleKeyInfo keyinfo;
keyinfo = Console.ReadKey();
do
{
keyinfo = Console.ReadKey();
debounceDispatcher.Throttle(5, param => hello());
}
while (keyinfo.Key != ConsoleKey.X);
}
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
hello();
}
private static void hello()
{
Console.WriteLine("Hello World 5 seconds");
}
}
这里是 DebouncingThrottling 类,您也可以找到 here:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Threading;
namespace SyncManager
{
public class DebounceDispatcher
{
private DispatcherTimer timer;
private DateTime timerStarted { get; set; } = DateTime.UtcNow.AddYears(-1);
/// <summary>
/// Debounce an event by resetting the event timeout every time the event is
/// fired. The behavior is that the Action passed is fired only after events
/// stop firing for the given timeout period.
///
/// Use Debounce when you want events to fire only after events stop firing
/// after the given interval timeout period.
///
/// Wrap the logic you would normally use in your event code into
/// the Action you pass to this method to debounce the event.
/// Example: https://gist.github.com/RickStrahl/0519b678f3294e27891f4d4f0608519a
/// </summary>
/// <param name="interval">Timeout in Milliseconds</param>
/// <param name="action">Action<object> to fire when debounced event fires</object></param>
/// <param name="param">optional parameter</param>
/// <param name="priority">optional priorty for the dispatcher</param>
/// <param name="disp">optional dispatcher. If not passed or null CurrentDispatcher is used.</param>
public void Debounce(int interval, Action<object> action,
object param = null,
DispatcherPriority priority = DispatcherPriority.ApplicationIdle,
Dispatcher disp = null)
{
// kill pending timer and pending ticks
timer?.Stop();
timer = null;
if (disp == null)
disp = Dispatcher.CurrentDispatcher;
// timer is recreated for each event and effectively
// resets the timeout. Action only fires after timeout has fully
// elapsed without other events firing in between
timer = new DispatcherTimer(TimeSpan.FromMilliseconds(interval), priority, (s, e) =>
{
if (timer == null)
return;
timer?.Stop();
timer = null;
action.Invoke(param);
}, disp);
timer.Start();
}
/// <summary>
/// This method throttles events by allowing only 1 event to fire for the given
/// timeout period. Only the last event fired is handled - all others are ignored.
/// Throttle will fire events every timeout ms even if additional events are pending.
///
/// Use Throttle where you need to ensure that events fire at given intervals.
/// </summary>
/// <param name="interval">Timeout in Milliseconds</param>
/// <param name="action">Action<object> to fire when debounced event fires</object></param>
/// <param name="param">optional parameter</param>
/// <param name="priority">optional priorty for the dispatcher</param>
/// <param name="disp">optional dispatcher. If not passed or null CurrentDispatcher is used.</param>
public void Throttle(int interval, Action<object> action,
object param = null,
DispatcherPriority priority = DispatcherPriority.ApplicationIdle,
Dispatcher disp = null)
{
// kill pending timer and pending ticks
timer?.Stop();
timer = null;
if (disp == null)
disp = Dispatcher.CurrentDispatcher;
var curTime = DateTime.UtcNow;
// if timeout is not up yet - adjust timeout to fire
// with potentially new Action parameters
if (curTime.Subtract(timerStarted).TotalMilliseconds < interval)
interval -= (int)curTime.Subtract(timerStarted).TotalMilliseconds;
timer = new DispatcherTimer(TimeSpan.FromMilliseconds(interval), priority, (s, e) =>
{
if (timer == null)
return;
timer?.Stop();
timer = null;
action.Invoke(param);
}, disp);
timer.Start();
timerStarted = curTime;
}
}
}
感谢所有帮助。
我检查过的其他链接试图帮助我理解: timers dispatcher youtube video
【问题讨论】:
-
Throtte的参数是 5,表示 5 毫秒。可能不是你的意思。试试 5000... -
刚切换到5000,结果一样。
标签: c# timer dispatcher throttling