如何提高 'ManagementEventWatcher' 逻辑的响应能力?
How to increase the responsiveness of 'ManagementEventWatcher' logic?
我订阅了 Win32_ProcessStartTrace
class 事件以在 PC 上的进程 运行 时发出通知:
Me.processStartWatcher =
New ManagementEventWatcher(New WqlEventQuery("SELECT * FROM Win32_ProcessStartTrace"))
但是,这似乎效率不高,因为在我 运行 一个可执行文件后需要 1 或 2 秒才能触发事件:
Private Sub ProcessStartWatcher_EventArrived(sender As Object, e As EventArrivedEventArgs) _
Handles processStartWatcher.EventArrived
If (Me.ProcessStartedEvent IsNot Nothing) Then
RaiseEvent ProcessStarted(Me, e)
End If
End Sub
这意味着如果一个进程是 运行 并且已经快速退出,那么我将不会收到通知。
我可以做些什么来提高 ManagementEventWatcher
对象的响应能力吗?
我试过设置 Timeout
属性 但是正如会员的描述所说,似乎与此目的无关。
您在 WMI 查询中使用 WITHIN
clause 来指定轮询间隔。该文章给出了大量警告,不建议使用小间隔。但无论如何都要勇往直前:
Me.processStartWatcher =
New ManagementEventWatcher(
New WqlEventQuery("SELECT * FROM Win32_ProcessStartTrace WITHIN 0.1"))
而且你会发现它根本没有任何区别,默认值已经尽可能快了。这是 Windows 中的体系结构,内核没有 'hook' 在创建进程时生成通知。重要的是,它可能对病毒扫描程序来说很重要。他们被迫修补 OS 以便能够跳入。实现此查询的 WMI 提供程序 (C:\Windows\System32\wbem\KrnlProv.dll) 不执行此操作。
另一种查看方法是使用流程自己实现它 class。例如:
Public Class ProcessMonitor
Public Event Started As Action(Of Integer)
Public Event Stopped As Action(Of Integer)
Public Sub New(interval As Integer)
Me.interval = interval
running = Scan()
timer = New Threading.Timer(AddressOf callback, Nothing, interval, 0)
End Sub
Private Sub callback(state As Object)
Dim active As HashSet(Of Integer) = Scan()
Dim started As IEnumerable(Of Integer) = active.Except(running)
Dim stopped As IEnumerable(Of Integer) = running.Except(active)
running = active
For Each pid As Integer In started
RaiseEvent started(pid)
Next
For Each pid As Integer In stopped
RaiseEvent stopped(pid)
Next
timer.Change(interval, 0)
End Sub
Private Function Scan() As HashSet(Of Integer)
Dim ret As New HashSet(Of Integer)
For Each proc As Process In Process.GetProcesses()
ret.Add(proc.Id)
Next
Return ret
End Function
Private running As HashSet(Of Integer)
Private timer As System.Threading.Timer
Private interval As Integer
End Class
带有使用它的示例程序:
Module Module1
Sub Main()
Dim monitor As New ProcessMonitor(100)
AddHandler monitor.Started, AddressOf Started
AddHandler monitor.Stopped, AddressOf Stopped
Console.ReadLine()
End Sub
Sub Started(pid As Integer)
Console.WriteLine("Started: {0}", Process.GetProcessById(pid).ProcessName)
End Sub
Sub Stopped(pid As Integer)
Console.WriteLine("Stopped: {0}", pid)
End Sub
End Module
没有区别。
我订阅了 Win32_ProcessStartTrace
class 事件以在 PC 上的进程 运行 时发出通知:
Me.processStartWatcher =
New ManagementEventWatcher(New WqlEventQuery("SELECT * FROM Win32_ProcessStartTrace"))
但是,这似乎效率不高,因为在我 运行 一个可执行文件后需要 1 或 2 秒才能触发事件:
Private Sub ProcessStartWatcher_EventArrived(sender As Object, e As EventArrivedEventArgs) _
Handles processStartWatcher.EventArrived
If (Me.ProcessStartedEvent IsNot Nothing) Then
RaiseEvent ProcessStarted(Me, e)
End If
End Sub
这意味着如果一个进程是 运行 并且已经快速退出,那么我将不会收到通知。
我可以做些什么来提高 ManagementEventWatcher
对象的响应能力吗?
我试过设置 Timeout
属性 但是正如会员的描述所说,似乎与此目的无关。
您在 WMI 查询中使用 WITHIN
clause 来指定轮询间隔。该文章给出了大量警告,不建议使用小间隔。但无论如何都要勇往直前:
Me.processStartWatcher =
New ManagementEventWatcher(
New WqlEventQuery("SELECT * FROM Win32_ProcessStartTrace WITHIN 0.1"))
而且你会发现它根本没有任何区别,默认值已经尽可能快了。这是 Windows 中的体系结构,内核没有 'hook' 在创建进程时生成通知。重要的是,它可能对病毒扫描程序来说很重要。他们被迫修补 OS 以便能够跳入。实现此查询的 WMI 提供程序 (C:\Windows\System32\wbem\KrnlProv.dll) 不执行此操作。
另一种查看方法是使用流程自己实现它 class。例如:
Public Class ProcessMonitor
Public Event Started As Action(Of Integer)
Public Event Stopped As Action(Of Integer)
Public Sub New(interval As Integer)
Me.interval = interval
running = Scan()
timer = New Threading.Timer(AddressOf callback, Nothing, interval, 0)
End Sub
Private Sub callback(state As Object)
Dim active As HashSet(Of Integer) = Scan()
Dim started As IEnumerable(Of Integer) = active.Except(running)
Dim stopped As IEnumerable(Of Integer) = running.Except(active)
running = active
For Each pid As Integer In started
RaiseEvent started(pid)
Next
For Each pid As Integer In stopped
RaiseEvent stopped(pid)
Next
timer.Change(interval, 0)
End Sub
Private Function Scan() As HashSet(Of Integer)
Dim ret As New HashSet(Of Integer)
For Each proc As Process In Process.GetProcesses()
ret.Add(proc.Id)
Next
Return ret
End Function
Private running As HashSet(Of Integer)
Private timer As System.Threading.Timer
Private interval As Integer
End Class
带有使用它的示例程序:
Module Module1
Sub Main()
Dim monitor As New ProcessMonitor(100)
AddHandler monitor.Started, AddressOf Started
AddHandler monitor.Stopped, AddressOf Stopped
Console.ReadLine()
End Sub
Sub Started(pid As Integer)
Console.WriteLine("Started: {0}", Process.GetProcessById(pid).ProcessName)
End Sub
Sub Stopped(pid As Integer)
Console.WriteLine("Stopped: {0}", pid)
End Sub
End Module
没有区别。