提高 FileSystemWatcher 的性能
Improving the Performance of FileSystemWatcher
我有以下代码,它注册一个 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);
}
我觉得这可能不是保持应用程序打开的最佳方式,但我不确定。
有人能给点建议吗?
看起来您正在坚持 运行 方法中的一个线程。不要那样做。而是保留一个静态参考。看起来您正在观看网络共享。不要期望高性能,因为这不仅涉及磁盘子系统,还涉及网络子系统(在您的终端和服务器上)。涉及的因素太多,无法预期在本机调用相同的 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();
};
}
我有以下代码,它注册一个 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);
}
我觉得这可能不是保持应用程序打开的最佳方式,但我不确定。
有人能给点建议吗?
看起来您正在坚持 运行 方法中的一个线程。不要那样做。而是保留一个静态参考。看起来您正在观看网络共享。不要期望高性能,因为这不仅涉及磁盘子系统,还涉及网络子系统(在您的终端和服务器上)。涉及的因素太多,无法预期在本机调用相同的 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();
};
}