Наблюдение за процессами WMI использует слишком много ЦП! Есть лучший способ?

Мне нужно наблюдать, когда определенные процессы запускаются или останавливаются на машине с Windows. В настоящее время я подключаюсь к системе WMI и запрашиваю ее каждые 5 секунд, но это вызывает скачок производительности процессора каждые 5 секунд, потому что WMI - это WMI. Есть ли лучший способ сделать это? Я мог бы просто составить список запущенных процессов и прикрепить к ним событие Exited через пространство имен System.Diagnostics, но обработчика событий для создания нет.

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
0
5 402
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Ответ принят как подходящий

Это не совсем то, как вы бы сделали это в реальном мире, но должно помочь. Похоже, это совсем не сильно влияет на мой процессор.

    static void Main(string[] args)
    {
        // Getting all instances of notepad
        // (this is only done once here so start up some notepad instances first)
        // you may want use GetProcessByPid or GetProcesses and filter them as required
        Process[] processesToWatch = Process.GetProcessesByName("notepad");

        foreach (var process in processesToWatch)
        {
            process.EnableRaisingEvents = true;
            process.Exited +=
                (s, e) => Console.WriteLine("An instance of notepad exited");
        }

        Thread watchThread = new Thread(() =>
            {
                while (true)
                {
                    Process[] processes = Process.GetProcesses();
                    foreach (var process in processes)
                    {
                        Console.WriteLine("{0}:{1}", process.Id, process.ProcessName);
                    }
                    // Don't dedicate a thread to this like I'm doing here
                    // setup a timer or something similiar
                    Thread.Sleep(2000);
                }
            });
        watchThread.IsBackground = true;
        watchThread.Start();

        Console.WriteLine("Polling processes and waiting for notepad process exit events");
        Console.ReadLine();
    }

Это тот путь, по которому я пошел после того, как не смог заставить WMI быть лучше для меня.

user43805 07.12.2008 07:23

Я использовал похожую технику для отслеживания всех запусков и завершений процессов. Даже при очень маленьком спящем режиме (50 мсек) в цикле мой процессор работает на ~ 0%. Как только PID получен таким образом, я вызываю Win32_Process и получаю дополнительную информацию о процессе, которой нет (или которую трудно получить без создания исключения) через класс Process.

Bosco 16.04.2014 07:31

У меня были скачки ЦП при прослушивании событий WMI в тех случаях, когда мне не удавалось должным образом отсоединиться от событий при выходе / очистке. Возможно, вы захотите проверить, не происходит ли «утечка» подписок на события WMI. На всякий случай отключитесь от мероприятия как можно раньше и убедитесь, что вы всегда это делаете.

Чтобы проиллюстрировать это дальше, вот пример из моя книга PowerShell, который прослушивает события WMI с помощью библиотеки PSEventing:

Add-PSSnapin PSEventing -ErrorAction SilentlyContinue

$queryString = @' SELECT * FROM __InstanceModificationEvent WITHIN 10 WHERE TargetInstance ISA 'Win32_Service' AND TargetInstance.Name = 'w3svc' AND TargetInstance.State = 'Stopped' '@

$query = New-Object System.Management.WQLEventQuery ` -argumentList $queryString

$watcher = New-Object System.Management.ManagementEventWatcher($query)

Connect-EventListener watcher EventArrived

$watcher.Start()

echo "Waiting for the W3CSVC service to stop..." Get-Event -wait | foreach { Write-Host -foreground Red "The W3SVC service has stopped!" }

$watcher.Stop()

Disconnect-EventListener watcher EventArrived

echo "done"

Если я не использую бит Disconnect-EventListener при выходе из скрипта, я получаю скачки ЦП в третий или четвертый раз, когда я присоединяюсь к событию. Я предполагаю, что система все еще пытается доставить события.

Если вы ищете только PID / имя ваших процессов, вы можете вместо этого захотеть получать события Win32_ProcessTrace, используя WQL-запрос, такой как «SELECT * FROM Win32_ProcessTrace WHERE TargetInstance.ProcessName = 'name'» если это применимо*.

Ошибка использования «SELECT * FROM __InstanceModificationEvent WITHIN 10 WHERE TargetInstance ISA 'Win32Process' AND TargetInstance.Name = 'name'» заключается в том, как это работает на серверной части. Если вы проверите wbemess.log в каталоге% windir% \ system32 \ wbem \ logs, вы заметите следующие журналы (с использованием __InstanceDeletionEvent):

(Wed Jul 22 13:58:31 2009.73889577) : Registering notification sink with query select * from __InstanceDeletionEvent within 10 where TargetInstance ISA 'Win32_Process' in namespace //./root/CIMV2.
(Wed Jul 22 13:58:31 2009.73889577) : Activating filter 047209E0 with query select * from __InstanceDeletionEvent within 10 where TargetInstance ISA 'Win32_Process' in namespace //./root/CIMV2.
(Wed Jul 22 13:58:31 2009.73889577) : Activating filter 0225E560 with query select * from __ClassOperationEvent where TargetClass isa "Win32_Process" in namespace //./root/CIMV2.
(Wed Jul 22 13:58:31 2009.73889577) : Activating filter 'select * from __ClassOperationEvent where TargetClass isa "Win32_Process"' with provider $Core
(Wed Jul 22 13:58:31 2009.73889587) : Activating filter 'select * from __InstanceDeletionEvent within 10 where TargetInstance ISA 'Win32_Process'' with provider $Core
(Wed Jul 22 13:58:31 2009.73889587) : Instituting polling query select * from Win32_Process to satisfy event query select * from __InstanceDeletionEvent within 10 where TargetInstance ISA 'Win32_Process'
(Wed Jul 22 13:58:31 2009.73889587) : Executing polling query 'select * from Win32_Process' in namespace '//./root/CIMV2'
(Wed Jul 22 13:58:31 2009.73889697) : Polling query 'select * from Win32_Process' done
(Wed Jul 22 13:58:41 2009.73899702) : Executing polling query 'select * from Win32_Process' in namespace '//./root/CIMV2'
(Wed Jul 22 13:58:41 2009.73899792) : Polling query 'select * from Win32_Process' done

Как видите, реальная реализация события на удаленном компьютере заключается в выполнении запроса к Win32_Process в интервале, который указан вашим значением в предложении WITHIN. В результате любые процессы, которые запускаются и останавливаются в этом опросе, никогда не вызовут событие.

Вы можете установить для предложения WITHIN небольшое значение, чтобы попытаться минимизировать этот эффект, но лучшим решением является использование истинного события, такого как Win32_ProcessTrace, которое должно срабатывать всегда.

* Обратите внимание, что MSDN указывает, что Win32_ProcessTrace требует для работы как минимум Windows XP на клиентском компьютере и Windows 2003 на сервере. Если вы работаете с более старой ОС, вы можете застрять при использовании запроса __InstanceModificationEvent.

В моем ответе здесь упоминается альтернатива, отличная от WMI: https://stackoverflow.com/a/50315772/3721646 Запросы WMI могут значительно снизить производительность ЦП, если они не спроектированы должным образом. Если внутреннее событие из класса Win32_Process используется для отслеживания события создания процесса, это сильно влияет на производительность. Альтернативный подход - использовать журналы аудита безопасности. Вы можете включить отслеживание процессов с помощью локальной политики безопасности или с помощью объекта групповой политики в случае нескольких компьютеров. После запуска отслеживания процессов вы можете подписаться на журналы событий безопасности с помощью настраиваемого XML-запроса для отслеживания определенных процессов, которые вас интересуют. Идентификатор события создания процесса - 4688. `

<QueryList>
 <Query Id = "0" Path = "Security">
   <Select Path = "Security">
       *[EventData[Data[@Name='NewProcessName'] ='C:\Windows\explorer.exe']]
       and
       *[System[(EventID=4688)]]
   </Select>
 </Query>
</QueryList>

Другие вопросы по теме