改进FileSystemWatcher的性能

本文关键字:性能 FileSystemWatcher 改进 | 更新日期: 2023-09-27 17:55:04

我有以下代码,注册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);
}

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

有谁能给点建议吗?

改进FileSystemWatcher的性能

看起来你在Run方法中抓住了一个线程。不要那样做。相反,保持一个静态引用。看起来你在看网络共享。不要期望高性能,因为这不仅涉及磁盘子系统,还涉及网络子系统(在您的终端和服务器上)。有太多的因素涉及到期望调用相同的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(); 
    };
}