避免一次在目录中出现太多错误 [英] Avoid Error too many changes at once in directory

查看:102
本文介绍了避免一次在目录中出现太多错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何避免C#中的FileSystemWatcher错误?

how to avoid the error of FileSystemWatcher in C#?

目录中一次更改太多

too many changes at once in directory

我必须检测网络共享上的所有更改. InternalBufferSize增加到8192 * 128

I have to detect all changes on a network share. The InternalBufferSize is increased to 8192 * 128

推荐答案

您应该做两件事:

  1. InternalBufferSize设置为最大支持值(65536).您尝试将其设置为"8192 * 128"大于在
  1. Set InternalBufferSize to the maximum supported value (65536). Your attempt to set it to "8192 * 128" is larger than the maximum supported value listed in the documentation, so you may not have increased the buffer size at all.
  2. Queue events from the FileSystemWatcher onto a background thread for processing.

这是第二点,尚未得到很好的理解,确实应该在MSDN上进行记录.在内部,FileSystemWatcher将更改事件排队到您设置了上述大小的内部缓冲区中.但是,至关重要的是,仅在事件处理程序返回后从该缓冲区中删除项目.这意味着事件处理程序引入的每个开销周期都会增加缓冲区填满的可能性.您应该做的是尽快清除FileSystemWatcher的有限队列,并将事件移到您自己的无限队列中,以可以处理的速率处理,或者在需要时放弃处理,但是要注意一些周围的情报.

It's the second point here that isn't well understood, and really should be documented on MSDN. Internally, FileSystemWatcher is queuing change events into that internal buffer you set the size of above. Critically however, items are only removed from that buffer after your event handler returns. This means every cycle of overhead your event handlers introduce increases the possibility of the buffer filling up. What you should do is clear the limited queue of the FileSystemWatcher as quickly as possible, and move the events into your own infinite queue, to process at the rate you can handle, or discard if you care to do so, but with some intelligence around it.

基本上,这就是我在代码中所做的事情.首先,我启动自己的调度程序线程:

Here's basically what I do in my code. First, I start my own dispatcher thread:

Dispatcher changeDispatcher = null;
ManualResetEvent changeDispatcherStarted = new ManualResetEvent(false);
Action changeThreadHandler = () =>
{
    changeDispatcher = Dispatcher.CurrentDispatcher;
    changeDispatcherStarted.Set();
    Dispatcher.Run();
};
new Thread(() => changeThreadHandler()) { IsBackground = true }.Start();
changeDispatcherStarted.WaitOne();

然后创建观察者.请注意正在设置的缓冲区大小.就我而言,我只关注目标目录中的更改,而不关注子目录中的更改:

Then I create the watcher. Note the buffer size being set. In my case, I only watch changes in the target directory, not subdirectories:

FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = path;
watcher.InternalBufferSize = 64 * 1024;
watcher.IncludeSubdirectories = false;

现在,我附加了事件处理程序,但是在这里,我将它们调用到我的调度程序上,而不是在监视程序线程中同步运行它们.是的,事件将由调度程序按顺序处理:

Now I attach my event handlers, but here I invoke them onto my dispatcher rather than running them synchronously in the watcher thread. Yes, the events will be processed in order by the dispatcher:

watcher.Changed += (sender, e) => changeDispatcher.BeginInvoke(new Action(() => OnChanged(sender, e)));
watcher.Created += (sender, e) => changeDispatcher.BeginInvoke(new Action(() => OnCreated(sender, e)));
watcher.Deleted += (sender, e) => changeDispatcher.BeginInvoke(new Action(() => OnDeleted(sender, e)));
watcher.Renamed += (sender, e) => changeDispatcher.BeginInvoke(new Action(() => OnRenamed(sender, e)));

最后,在处置FileSystemWatcher之后(您正在这样做,对吗?),您需要关闭调度程序:

And finally, after disposing of the FileSystemWatcher (you were doing that, right?), you need to shut down your dispatcher:

watcher.Dispose()
changeDispatcher.BeginInvokeShutdown(DispatcherPriority.Normal);

就是这样.我自己在网络和本地场景中都遇到了这个问题.使用这种方法后,即使尽快将空文件敲入要监视的目录,我也无法再次生成此错误.如果您在这种情况下确实设法以某种方式耗尽了缓冲区(我不确定这是不可能的,那么上游的API可能会更慢),这里还有进一步优化的余地.但是,只要您的调度程序超过了临界点",即发送方无法以比分发事件更快的速度发布事件,您将永远不会积压,因此也永远不会浪费缓冲区.我相信这种方法会将您带入安全区域.

And that's it. I was getting this problem myself, both in network and local scenarios. After using this approach, I wasn't able to generate this error again, even when hammering out empty files to watched directories as fast as possible. If you did ever manage to somehow exhaust the buffer in this case (which I'm not sure is possible, the API upstream is probably slower), there's still further room for optimization here. As long as your dispatcher is over the "tipping point" though, where the sender can't post the events faster than you can dispatch them, you'll never get a backlog, and hence never blow the buffer. I believe this approach puts you into that safe area.

这篇关于避免一次在目录中出现太多错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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