【问题标题】:WMI call takes too much time when system Starts/ReStarts系统启动/重新启动时 WMI 调用需要太多时间
【发布时间】:2012-05-08 16:49:42
【问题描述】:

我想获取Windows服务的路径,

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

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

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

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

【问题讨论】:

  • 你试过用 PowerShell 代替吗?
  • 我没有使用过 powershell.. 比 WMI 调用有任何特定优势...

标签: c# .net performance windows-services wmi


【解决方案1】:

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

的句子
SELECT PathName FROM Win32_Service Where Name='MyService'

更新

@Bacon的观察是非常正确的,因为你知道要检索的服务的名称,你可以构建Win32_Service的对象路径,看起来像

Win32_Service.Name="ServiceName"

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

【讨论】:

  • 由于您是通过NameWin32_Service class 的关键属性)过滤的,因此直接访问实例而不进行搜索会更快:string path = "Win32_Service.Name=\"MyService\""; ManagementObject service = new ManagementObject(path); string pathName = (string) service.GetPropertyValue("PathName"); 但我认为作者是说 WMI 初始化需要很长时间,而不是查询执行时间太长。
  • 是的,但是使用查询您必须访问每个 Name 实例的 Name 属性。因此,它检索的是一个实例的 25 个属性,而不是所有实例的一个属性(在我的 64 位 Windows 7 Professional 笔记本电脑上,有 188 个服务)。在对检索服务的PathName 属性的每种方法进行 1,000 次迭代的快速测试中,按路径构造ManagementObject 只需不到 10 秒,而使用ManagementObjectSearcher 大约需要两分钟。删除任何 using 块并从后者中使用 LINQ 确实可以将其缩短到大约一分钟。
  • @Bacon,我误解了您关于使用ManagementObject 而不是ManagementObjectSearcher 的实例的对象路径的原始评论,您的观察非常正确,直接获得ManagementObject 也很多比获得ManagementObjectSearcher 并枚举每个实例要好。
【解决方案2】:

由于您通过NameWin32_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 Professional 系统上,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

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-08-14
      • 2017-09-10
      • 1970-01-01
      • 2018-07-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-04
      相关资源
      最近更新 更多