提高 FileSystemWatcher 的性能

Improving the Performance of FileSystemWatcher

我有以下代码,它注册一个 FileSystemWatcher 然后运行一些方法 DoRequiedWork() 每当指定文件上发生写入事件时。那里还有一些逻辑可以防止每次写入时触发多个事件(lastReadlastWriteTime):

// To prevent multiple events from firing
static DateTime lastRead = DateTime.MinValue;
static string UserName = GetUserName();

private static void Run()
{
    // Create a new FileSystemWatcher and set its properties.
    var watcher = new FileSystemWatcher
    {
        Path = $@"\file\home$\{UserName}\Application Data",
        NotifyFilter =  
            NotifyFilters.LastWrite,
        Filter = "filetowatch.txt"
    };

    // Activate
    watcher.Changed += OnChanged;
    watcher.EnableRaisingEvents = true;

    while (true)
    {
        System.Threading.Thread.Sleep(10000);
    }
}

private static void OnChanged(object source, FileSystemEventArgs e)
{
    var lastWriteTime = File.GetLastWriteTime(e.FullPath);

    if (lastWriteTime == lastRead) return;

    DoRequiredWork();

    lastRead = lastWriteTime; 
}

我想使用 c++ api ReadDirectoryChangesW 来实现这一点以提高性能,但我不知道该怎么做。

我查看了pinvoke,可以看到签名可以定义为:

[DllImport("kernel32.dll")]
 static extern bool ReadDirectoryChangesW(IntPtr hDirectory, IntPtr lpBuffer,
    uint nBufferLength, bool bWatchSubtree, uint dwNotifyFilter, out uint
    lpBytesReturned, IntPtr lpOverlapped,
    ReadDirectoryChangesDelegate lpCompletionRoutine);  

我想开始研究如何创建它,但首先要检查它是否真的比标准的托管 c# FileSystemWatcher 表现得更好。

或者(或除此之外),我想知道是否有更好的方法将应用程序 运行 保留在后台(没有 UI),而不是:

while (true)
{
    System.Threading.Thread.Sleep(10000);
}

我觉得这可能不是保持应用程序打开的最佳方式,但我不确定。

有人能给点建议吗?

看起来您正在坚持 运行 方法中的一个线程。不要那样做。而是保留一个静态参考。看起来您正在观看网络共享。不要期望高性能,因为这不仅涉及磁盘子系统,还涉及网络子系统(在您的终端和服务器上)。涉及的因素太多,无法预期在本机调用相同的 API 会突然带来巨大的性能提升。

static FileSystemWatcher watcher;

private static void Run()
{
    // Create a new FileSystemWatcher and set its properties.
    // if you're watching a network share, don't expect huge performance
    // as the network is involved
    watcher = new FileSystemWatcher
    {
        Path = $@"\file\home$\{UserName}\Application Data",
        NotifyFilter =  
            NotifyFilters.LastWrite,
        Filter = "filetowatch.txt"
    };

    // Activate
    watcher.Changed += OnChanged;
    watcher.EnableRaisingEvents = true;

    AppDomain.CurrentDomain.DomainUnload += (s,e) => { 
      var w = watcher as IDisposable;
      if (w != null) w.Dispose(); 
    };
}