2016-07-05 3 views
-1

У меня есть следующий код, который регистрирует FileSystemWatcher, а затем запускает некоторый метод. DoRequiedWork() Всякий раз, когда в указанном файле происходит событие записи. Существует также определенная логика там, чтобы предотвратить множественные события от стрельбы по каждой записи (с lastRead и lastWriteTime):Улучшение производительности FileSystemWatcher

// 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 = [email protected]"\\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++ апи 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.

В качестве альтернативы (или в дополнение к нему), я хотел бы знать, если есть лучший способ держать приложение работает в фоновом режиме (без пользовательского интерфейса), чем:

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

Как я получаю чувство это может быть не лучший способ открыть приложение, но я не уверен.

Может ли кто-нибудь посоветовать?

+1

[ 'FileSystemWatcher' УЖЕ использует' ReadDirectoryChanges'] (http://referencesource.microsoft.com/#System/services/io/system/io/FileSystemWatcher.cs), так что вы вряд ли улучшить положение вещей делая это самостоятельно. –

+1

Во время разработки .NET Core 1.0 Microsoft выявляет несколько проблем производительности в этой области. Вам придется подождать, пока они приземлится на платформе .NET Framework, или вы разработаете RTM-приложение .NET Core 1.0 прямо сейчас. –

+1

@MatthewWatson, который не является 100% истинным, если у Microsoft есть ошибки в этом классе. –

ответ

2

Похоже, вы держитесь за нить в своем методе 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 = [email protected]"\\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(); 
    }; 
} 
+0

Спасибо за ваш ответ Рене. Когда вы говорите, что я «держусь за поток», вы ссылаетесь на цикл while (true) {sleep}? Мне нужен этот FileWatcher, чтобы ВСЕГДА следить за необходимой папкой и не мог придумать другой способ сделать это. Другой вариант - зарегистрировать подписку «MOF», но они (досадно) не могут запускать exe или shell-программы, которые это то, что мне нужно сделать, когда обнаружено изменение файла. – Bassie

+1

Где вы это называете? – rene

+0

Это в C# Executable ('Run()' только что вызывается внутри 'Main()'), а обработчик событий позволяет мне вызвать второй exe. Когда я попытался создать WMI FileWatcher с использованием подписок MOF и WQL, он потерпел неудачу, потому что они не могут взаимодействовать с пользовательским интерфейсом или вызывать любые команды оболочки.Причина, по которой я изначально предпочитал MOF/WQL, заключается в том, что они не требуют, чтобы EXE работала в фоновом режиме для наблюдения за папкой, тогда как C# 'FileSystemWatcher' делает (CLARITY -' DoRequiredWork() 'в вопросе вызывает отдельный EXE из файловая система) – Bassie