代码之家  ›  专栏  ›  技术社区  ›  Joel Mueller

反应式扩展与FileSystemWatcher之比较

  •  17
  • Joel Mueller  · 技术社区  · 16 年前

    FileSystemWatcher长期以来一直困扰着我的一个问题是它为一个文件的单个逻辑更改触发多个事件的方式。我知道为什么会这样,但我不想在意-我只想重新分析文件一次,而不是连续4-6次。理想情况下,只有在给定文件发生更改时才会触发事件,而不是一路上的每一步。

    这些年来,我想出了各种各样的方法来解决这个问题,有不同程度的丑陋。我原以为反应式扩展是最终的解决方案,但有些事情我做得不对,我希望有人能指出我的错误。

    我有一个扩展方法:

    public static IObservable<IEvent<FileSystemEventArgs>> GetChanged(this FileSystemWatcher that)
    {
        return Observable.FromEvent<FileSystemEventArgs>(that, "Changed");
    }
    

    BufferWithTime

    var bufferedChange = watcher.GetChanged()
        .Select(e => e.EventArgs.FullPath)
        .BufferWithTime(TimeSpan.FromSeconds(1))
        .Where(e => e.Count > 0)
        .Select(e => e.Distinct());
    

    Distinct() 调用时,我看到四个调用中的每一个都包含两个相同的事件—因此有一些缓冲正在进行。增加传递到的时间跨度 缓冲时间 似乎没有效果-我高达20秒的行为没有任何变化。

    这是我第一次涉足Rx,所以我可能错过了一些明显的东西。我做错了吗?有更好的方法吗?谢谢你的建议。。。

    4 回复  |  直到 16 年前
        1
  •  11
  •   hko    10 年前

    当然,在监视一个文件的上下文中,这个主题可以忽略不计,因为FileSystemWatcher在跟踪单个文件的大小时,每3秒只触发一个更改的事件

    _fileSystemWatcher.NotifyFilter = NotifyFilters.Size | ....
    

    但假设FileSystemWatcher会连续触发许多事件(可能许多文件被更改/重命名/创建),其他人会读到:

    Throttle 有点误导。。它禁止任何射击,直到时间跨度时间过去 一个事件。意思是:当你用这样的东西时,它永远不会开火 Throttle(TimeSpan.FromMilliseconds(200)) ,每次事件之后都会暂停<所以这并不是人们期望的“节流”。当你想等到用户停止输入时,这对用户输入很有好处。这不利于负载节流。

    BufferWithTime 也不是你想要的:它只是填充了一个时间缓冲区。如果每个事件的初始负载很高,比如打开到webservice的连接,那么就很好了。在这种情况下,您希望每“time”秒批处理一次事件。但在负载平衡时不是这样,因为事件的数量不会改变。

    Sample(TimeSpan time) 方法:它接受一个时间跨度内的最后一个事件,这是“真正的”节流阀。我觉得Rx的人真的搞错了这个案子的名字。

        2
  •  4
  •   KingCrunch    13 年前

    var obs = from n in Enumerable.Range(1, 40).ToObservable()
        group n by n / 10 into g
        select new { g.Key, Obs = g.Throttle(TimeSpan.FromMilliseconds(10.0)) } into h
        from x in h.Obs
        select x;
    obs.Subscribe(x => Console.WriteLine(x));
    

    输出:

    9 
    19 
    29 
    39 
    40 
    

    每一组的( n/10 )最后观察到的整数。

        3
  •  3
  •   Joel Mueller    16 年前

    我的错。不知何故,我有多个FileSystemWatchers监视彼此的文件夹。每个观察者都会触发一次可观察到的,但是 BufferWithTime 似乎工作正常。我仍然需要弄清楚为什么我的观察者会对我认为配置为忽略的文件夹触发事件,但这与Rx或这个问题无关。

    事实上,也许我可以在这个问题上下赌注,转而让一个观察者监视父文件夹,使用Rx从我不感兴趣的文件夹中过滤出事件。

        4
  •  3
  •   Scott Weinstein    16 年前

    BufferWithTime.Where().Select(…)将执行此任务,但您真正需要的是 Throttle()

    推荐文章