我正在监听硬件事件消息,但我需要对其进行反跳以避免太多查询。
这是一个发送机器状态的硬件事件,我必须将其存储在数据库中以用于统计目的,有时它的状态会经常变化(闪烁?)。在这种情况下,我只想存储“稳定”状态,并且我想通过在将状态存储到数据库之前简单地等待 1-2 秒来实现它。
这是我的代码:
private MachineClass connect()
{
try
{
MachineClass rpc = new MachineClass();
rpc.RxVARxH += eventRxVARxH;
return rpc;
}
catch (Exception e1)
{
log.Error(e1.Message);
return null;
}
}
private void eventRxVARxH(MachineClass Machine)
{
log.Debug("Event fired");
}
我将这种行为称为“去抖”:等待几次才能真正完成其工作:如果在去抖时间内再次触发同一事件,我必须驳回第一个请求并开始等待去抖时间以完成第二个事件。
管理它的最佳选择是什么?只是一个一次性计时器?
要解释“debounce”功能,请参阅以下关键事件的 javascript 实现:http://benalman.com/code/projects/jquery-throttle-debounce/examples/debounce/
我用它来消除事件并取得了一些成功:
public static Action<T> Debounce<T>(this Action<T> func, int milliseconds = 300)
{
var last = 0;
return arg =>
{
var current = Interlocked.Increment(ref last);
Task.Delay(milliseconds).ContinueWith(task =>
{
if (current == last) func(arg);
task.Dispose();
});
};
}
Usage
Action<int> a = (arg) =>
{
// This was successfully debounced...
Console.WriteLine(arg);
};
var debouncedWrapper = a.Debounce<int>();
while (true)
{
var rndVal = rnd.Next(400);
Thread.Sleep(rndVal);
debouncedWrapper(rndVal);
}
它可能不像 RX 那样强大,但很容易理解和使用。
后续2020-02-03
使用取消令牌修改了 @collie 的解决方案,如下所示
public static Action<T> Debounce<T>(this Action<T> func, int milliseconds = 300)
{
CancellationTokenSource? cancelTokenSource = null;
return arg =>
{
cancelTokenSource?.Cancel();
cancelTokenSource = new CancellationTokenSource();
Task.Delay(milliseconds, cancelTokenSource.Token)
.ContinueWith(t =>
{
if (t.IsCompletedSuccessfully)
{
func(arg);
}
}, TaskScheduler.Default);
};
}
Notes:
- Calling
Cancel
足以处理 CTS
- 成功完成的 CTS 在下一次调用之前不会被取消/处置
- 正如 @collie 所指出的,任务已被释放,因此无需调用
Dispose
在任务上
我以前没有使用过取消令牌,可能没有正确使用它们。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)