WMI 调用在系统启动/重新启动时花费太多时间

本文关键字:太多 时间 重新启动 调用 系统启动 WMI | 更新日期: 2023-09-27 18:33:28

我想获取 Windows 服务的路径,

var managementObjectSearcher = new ManagementObjectSearcher("Select * from Win32_Service where serviceName = MyService");

这段代码是由其他一些服务的构造函数编写的......

当系统启动并运行时一切正常,但是如果我重新启动系统,请为此调用放置StopWatch类,它表明由于此调用,该服务需要35-45秒才能启动。

任何提高系统重启性能的建议...

WMI 调用在系统启动/重新启动时花费太多时间

Windows32_Services 类不存在,因此假设您使用的是 Win32_Service WMI 类,您可以提高性能,仅返回要使用的属性,在本例中为 PathName ,因此请将 WQL 句子更改为

SELECT PathName FROM Win32_Service Where Name='MyService'

更新

@Bacon的观察结果非常正确,因为您知道要检索的服务的名称,因此您可以构建Win32_Service的对象路径,如下所示

Win32_Service.Name="ServiceName"

然后使用 ManagementObject 类,您可以以最快的方式将实例检索到服务。

由于您是通过 Name 检索服务的,这是Win32_Service class的关键属性,请尝试直接检索实例而不是搜索它:

string GetMyServicePath()
{
    string path = "Win32_Service.Name='"MyService'"";
    using (ManagementObject service = new ManagementObject(path))
        return (string) service.GetPropertyValue("PathName");
}

以下是我用来比较直接检索与搜索的快速基准:

private const int LoopIterations = 1000;
private const string ServiceClass = "Win32_Service";
private const string ServiceName = "MyService";
private const string ServiceProperty = "PathName";
private static readonly string ServicePath = string.Format("{0}.Name='"{1}'"", ServiceClass, ServiceName);
private static readonly string ServiceQuery = string.Format(
    "SELECT {0} FROM {1} Where Name='"{2}'"",
    ServiceProperty, ServiceClass, ServiceName
);
private static ManagementObjectSearcher ServiceSearcher = new ManagementObjectSearcher(ServiceQuery);
static void Main(string[] args)
{
    var watch = new Stopwatch();
    watch.Start();
    for (int i = 0; i < LoopIterations; i++)
    {
        var servicePath = GetServicePathByKey();
    }
    watch.Stop();
    Console.WriteLine(
        "{0:N0} iterations of GetServicePathByKey() took {1:N0} milliseconds",
        LoopIterations, watch.ElapsedMilliseconds
    );
    watch.Restart();
    for (int i = 0; i < LoopIterations; i++)
    {
        var servicePath = GetServicePathFromExistingSearcher();
    }
    watch.Stop();
    Console.WriteLine(
        "{0:N0} iterations of GetServicePathFromExistingSearcher() took {1:N0} milliseconds",
        LoopIterations, watch.ElapsedMilliseconds
    );
    watch.Restart();
    for (int i = 0; i < LoopIterations; i++)
    {
        var servicePath = GetServicePathFromNewSearcher();
    }
    watch.Stop();
    Console.WriteLine(
        "{0:N0} iterations of GetServicePathFromNewSearcher() took {1:N0} milliseconds",
        LoopIterations, watch.ElapsedMilliseconds
    );
}
static string GetServicePathByKey()
{
    using (var service = new ManagementObject(ServicePath))
        return (string) service.GetPropertyValue(ServiceProperty);
}
static string GetServicePathFromExistingSearcher()
{
    using (var results = ServiceSearcher.Get())
    using (var enumerator = results.GetEnumerator())
    {
        if (!enumerator.MoveNext())
            throw new Exception();
        return (string) enumerator.Current.GetPropertyValue(ServiceProperty);
    }
}
static string GetServicePathFromNewSearcher()
{
    using (var searcher = new ManagementObjectSearcher(ServiceQuery))
    using (var results = searcher.Get())
    using (var enumerator = results.GetEnumerator())
    {
        if (!enumerator.MoveNext())
            throw new Exception();
        return (string) enumerator.Current.GetPropertyValue(ServiceProperty);
    }
}

直接枚举搜索者结果的速度与我所能达到的速度差不多,比使用 foreach 块略快,比使用 LINQ 快两倍。 在我的 64 位 Windows 7 专业版系统上,ServiceName常量设置为 Power 我得到了以下结果:

1,000 iterations of GetServicePathByKey() took 8,263 milliseconds
1,000 iterations of GetServicePathFromExistingSearcher() took 64,265 milliseconds
1,000 iterations of GetServicePathFromNewSearcher() took 64,875 milliseconds

如果困扰您的是 WMI 的"延迟",则不必使用 WMI 来获取服务的路径,即可执行文件名称。你也可以P/invoke QueryServiceConfig。

http://www.pinvoke.net/default.aspx/advapi32/queryserviceconfig.html