C# 事件去抖动 [英] C# event debounce

查看:24
本文介绍了C# 事件去抖动的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在侦听硬件事件消息,但我需要对其进行去抖动以避免过多查询.

I'm listening to a hardware event message, but I need to debounce it to avoid too many queries.

这是一个发送机器状态的硬件事件,我必须将它存储在数据库中以用于统计目的,有时它的状态会经常变化(闪烁?).在这种情况下,我只想存储一个稳定"状态,我想通过在将状态存储到数据库之前简单地等待 1-2 秒来实现它.

This is an hardware event that sends the machine status and I have to store it in a database for statistical purposes, and it sometimes happens that its status changes very often (flickering?). In this case I would like to store only a "stable" status and I want to implement it by simply waiting for 1-2s before storing the status to the database.

这是我的代码:

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

我称这种行为为去抖动":等待几次才能真正完成它的工作:如果在去抖动时间内再次触发相同的事件,我必须关闭第一个请求并开始等待去抖动时间以完成第二个活动.

I call this behaviour "debounce": wait a few times to really do its job: if the same event is fired again during the debounce time, I have to dismiss the first request and start to wait the debounce time to complete the second event.

管理它的最佳选择是什么?只是一个一次性定时器?

What is the best choice to manage it? Simply a one-shot timer?

要解释去抖动"功能,请参阅关键事件的 javascript 实现:http://benalman.com/code/projects/jquery-throttle-去抖动/示例/去抖动/

To explain the "debounce" function please see this javascript implementation for key events: http://benalman.com/code/projects/jquery-throttle-debounce/examples/debounce/

推荐答案

这不是从头开始编写代码的微不足道的请求,因为有几个细微差别.一个类似的场景是监视 FileSystemWatcher 并等待大副本后事情安静下来,然后再尝试打开修改过的文件.

This isn't a trivial request to code from scratch as there are several nuances. A similar scenario is monitoring a FileSystemWatcher and waiting for things to quiet down after a big copy, before you try to open the modified files.

.NET 4.5 中的反应式扩展被创建来处理这些场景.您可以轻松地使用它们通过诸如 油门缓冲区, 窗口示例.您将事件发布到 主题,对其应用窗口函数之一,例如仅当 X 秒或 Y 事件没有活动时才收到通知,然后订阅通知.

Reactive Extensions in .NET 4.5 were created to handle exactly these scenarios. You can use them easily to provide such functionality with methods like Throttle, Buffer, Window or Sample. You post the events to a Subject, apply one of the windowing functions to it, for example to get a notification only if there was no activity for X seconds or Y events, then subscribe to the notification.

Subject<MyEventData> _mySubject=new Subject<MyEventData>();
....
var eventSequenc=mySubject.Throttle(TimeSpan.FromSeconds(1))
                          .Subscribe(events=>MySubscriptionMethod(events));

Throttle 返回滑动窗口中的最后一个事件,仅当窗口中没有其他事件时.任何事件都会重置窗口.

Throttle returns the last event in a sliding window, only if there were no other events in the window. Any event resets the window.

您可以在 此处找到关于时移函数的非常好的概述

当你的代码接收到事件时,你只需要使用 OnNext 将其发布到主题:

When your code receives the event, you only need to post it to the Subject with OnNext:

_mySubject.OnNext(MyEventData);

如果您的硬件事件显示为典型的 .NET 事件,您可以使用 Observable.FromEventPattern,如图这里:

If your hardware event surfaces as a typical .NET Event, you can bypass the Subject and manual posting with Observable.FromEventPattern, as shown here:

var mySequence = Observable.FromEventPattern<MyEventData>(
    h => _myDevice.MyEvent += h,
    h => _myDevice.MyEvent -= h);  
_mySequence.Throttle(TimeSpan.FromSeconds(1))
           .Subscribe(events=>MySubscriptionMethod(events));

您还可以从 Tasks 创建 observables,将事件序列与 LINQ 运算符结合起来以请求例如:使用 Zip 的不同硬件事件对,使用另一个事件源来绑定 Throttle/Buffer 等,添加延迟等等.

You can also create observables from Tasks, combine event sequences with LINQ operators to request eg: pairs of different hardware events with Zip, use another event source to bound Throttle/Buffer etc, add delays and a lot more.

Reactive Extensions 可作为 NuGet 包使用,因此添加起来非常容易将它们添加到您的项目中.

Reactive Extensions is available as a NuGet package, so it's very easy to add them to your project.

Stephen Cleary 的书C# 中的并发性"是一个非常关于 Reactive Extensions 以及其他方面的资源,并解释了如何使用它以及它如何与 .NET 中的其他并发 API(如任务、事件等)相适应.

Stephen Cleary's book "Concurrency in C# Cookbook" is a very good resource on Reactive Extensions among other things, and explains how you can use it and how it fits with the rest of the concurrent APIs in .NET like Tasks, Events etc.

Rx 简介 是一系列优秀的文章(我从那里复制了示例),并附有几个示例.

Introduction to Rx is an excellent series of articles (that's where I copied the samples from), with several examples.

更新

使用您的具体示例,您可以执行以下操作:

Using your specific example, you could do something like:

IObservable<MachineClass> _myObservable;

private MachineClass connect()
{

    MachineClass rpc = new MachineClass();
   _myObservable=Observable
                 .FromEventPattern<MachineClass>(
                            h=> rpc.RxVARxH += h,
                            h=> rpc.RxVARxH -= h)
                 .Throttle(TimeSpan.FromSeconds(1));
   _myObservable.Subscribe(machine=>eventRxVARxH(machine));
    return rpc;
}

这当然可以大大改进 - observable 和订阅都需要在某个时候处理.此代码假定您只控制一个设备.如果你有很多设备,你可以在类中创建 observable,以便每个 MachineClass 公开和处理自己的 observable.

This can be improved vastly of course - both the observable and the subscription need to be disposed at some point. This code assumes that you only control a single device. If you have many devices, you could create the observable inside the class so that each MachineClass exposes and disposes its own observable.

这篇关于C# 事件去抖动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆