改进FileSystemWatcher的性能
本文关键字:性能 FileSystemWatcher 改进 | 更新日期: 2023-09-27 17:55:04
我有以下代码,注册FileSystemWatcher
,然后在指定文件上发生写事件时运行一些方法DoRequiedWork()
。还有一些逻辑在那里,以防止多个事件从每次写入触发(与lastRead
和lastWriteTime
):
// 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);
}
我感觉这可能不是保持应用打开的最佳方式,但我不确定。
有谁能给点建议吗?
看起来你在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();
};
}