【问题标题】:WMI Poor PerformanceWMI 性能不佳
【发布时间】:2010-12-18 17:39:38
【问题描述】:

我用 C# 编写了一个代码,它使用 WMI (System.Management) 将逻辑驱动器映射到它们的物理磁盘。 代码运行良好,但速度很慢。 在我的机器(Windows 7 x64,双核,3 GB RAM)中,它运行至少 1 秒。 1秒对我来说太慢了,即使是0.1也足以完成。 我非常痛心的是,这个功能可以在不到 0.1 秒的时间内完成。

是否有任何 Win32API 函数可以提供帮助?

还有其他建议吗?

这是我目前的代码:

List<Dictionary<string, string>> results = new List<Dictionary<string, string>>();

using (ManagementClass diskDriveClass = new ManagementClass(@"Win32_Diskdrive"))
{
    using (ManagementObjectCollection diskDrives = diskDriveClass.GetInstances())
    {
        foreach (ManagementObject diskDrive in diskDrives)
        {
            string deviceId = (string)diskDrive["DeviceId"];
            Dictionary<string, string> logicalDisksResults = new Dictionary<string, string>();
            Trace.WriteLine(deviceId);

            using (ManagementObjectCollection relatedPartitions = diskDrive.GetRelated("Win32_DiskPartition"))
            {
                foreach (ManagementObject relatedPartition in relatedPartitions)
                {
                    Trace.WriteLine("-\t" + relatedPartition["Name"]);

                    using (ManagementObjectCollection relatedLogicalDisks = relatedPartition.GetRelated("Win32_LogicalDisk"))
                    {
                        foreach (ManagementBaseObject relatedLogicalDisk in
                        relatedLogicalDisks)
                        {
                            Trace.WriteLine("\t-\t" + relatedLogicalDisk["Name"] + " " + relatedLogicalDisk["FileSystem"]);
                            logicalDisksResults.Add((string)relatedLogicalDisk["Name"], (string)relatedLogicalDisk["FileSystem"]);
                        }
                    }
                }
            }

            results.Add(logicalDisksResults);
        }
    }
}

【问题讨论】:

  • 你能发布你的选项定义吗?
  • 对不起,我的错,我修复了上面的代码。我最初没有使用任何选项,我只是试图提高性能,但这没有帮助。

标签: c# .net performance wmi disk


【解决方案1】:

这里有一些代码至少在我的系统上运行得更快(从客观的角度来看)并给出相同的结果。由于驱动器列表几乎不可能每秒更改,我不确定您为什么如此关心,但无论如何,看看这是否让您更快乐。您可以通过删除在开始时获取 Win32_DiskDrive 的代码来稍微加快它,但祝它在 0.1 秒内运行 :)

Dictionary> 结果 = new Dictionary>(); ManagementClass diskPartMap = null; ManagementObjectCollection diskPartIns = null; ManagementClass partLogicalMap = null; ManagementObjectCollection partLogicalIns = null; 尝试 { 使用 (ManagementClass diskDriveClass = new ManagementClass("Win32_Diskdrive")) { 使用 (ManagementObjectCollection diskDrives = diskDriveClass.GetInstances()) { foreach(磁盘驱动器中的管理对象磁盘驱动器) { results.Add((string)diskDrive["DeviceId"], new Dictionary()); } } } Dictionary partToDisk = new Dictionary(); Dictionary partToLogical = new Dictionary(); diskPartMap = new ManagementClass("Win32_DiskDriveToDiskPartition"); diskPartIns = diskPartMap.GetInstances(); foreach(diskPartIns 中的 ManagementObject diskDrive) { ManagementObject o = new ManagementObject((string)diskDrive["Antecedent"]); partToDisk.Add((string)diskDrive["Dependent"], o); } partLogicalMap = new ManagementClass("Win32_LogicalDiskToPartition"); partLogicalIns = partLogicalMap.GetInstances(); foreach(部分LogicalIns中的ManagementObject diskDrive) { ManagementObject o = new ManagementObject((string)diskDrive["Dependent"]); string s = (string)diskDrive["Antecedent"]; partToLogical.Add(s, o); } foreach(partToDisk 中的 KeyValuePair 对) { string deviceId = (string)pair.Value["DeviceId"]; 字典 dict = null; if (!results.ContainsKey(deviceId)) { dict = new Dictionary(); 结果[deviceId] = 字典; } 别的 { dict = 结果[deviceId]; } if (partToLogical.ContainsKey(pair.Key)) { ManagementObject o = partToLogical[pair.Key]; dict.Add((string)o["Name"], (string)o["FileSystem"]); } } } 最后 { if (diskPartIns != null) { diskPartIns.Dispose(); diskPartIns = null; } if (diskPartMap != null) { diskPartMap.Dispose(); 磁盘部分映射 = 空; } if (partLogicalIns != null) { partLogicalIns.Dispose(); partLogicalIns = null; } if (partLogicalMap != null) { partLogicalMap.Dispose(); 部分逻辑映射=空; } }

【讨论】:

  • 非常感谢,你帮了我很多! :-) 你的代码在我的机器上运行速度比我的快 4 倍。另外,根据您对 Win32_LogicalDiskToPartition 的想法,我成功地使性能变得更好,现在它的运行速度比我的第一个版本快 23 倍。 :D
【解决方案2】:

这是我的最终代码,比第一个版本快 x23,基于使用 Win32_LogicalDiskToPartition 的暴君想法。

    private static Regex _logicalDiskNameRegex = new Regex("(?<=\")[^\"]*(?=\")");
    private static Regex _partitionDiskIndexRegex = new Regex("(?<=\"Disk #)\\d+");

    public static Dictionary<string, string>[] GetPhisicalHardDiskToDriveLettersMap()
    {
        DriveInfo[] driveInfoArr = DriveInfo.GetDrives();

        DriveInfo lastDriveInfo = null;
        Dictionary<string, DriveInfo> driveInfos = new Dictionary<string, DriveInfo>(driveInfoArr.Length);

        foreach (DriveInfo driveInfo in driveInfoArr)
        {
            if (driveInfo.DriveType == DriveType.Fixed)
            {
                driveInfos.Add(driveInfo.Name.Substring(0, 2), driveInfo);
                lastDriveInfo = driveInfo;
            }
        }

        if (driveInfos.Count == 1 && lastDriveInfo != null)
        {
            return new Dictionary<string, string>[]
        {
            new Dictionary<string, string>()
            {
                {lastDriveInfo.Name.Substring(0, 2), lastDriveInfo.DriveFormat}
            }
        };
        }

        Dictionary<string, Dictionary<string, string>> results = new Dictionary<string, Dictionary<string, string>>();

        using (ManagementClass partLogicalMap = new ManagementClass("Win32_LogicalDiskToPartition"))
        {
            using (ManagementObjectCollection partLogicalIns = partLogicalMap.GetInstances())
            {
                foreach (ManagementObject diskDrive in partLogicalIns)
                {
                    bool lazySuccess = false;

                    string driveName = null;
                    string driveFileSystem = null;
                    string physicalHardDisk = null;

                    string logicalDiskPath = (string)diskDrive["Dependent"];
                    string partitionPath = (string)diskDrive["Antecedent"];
                    Trace.WriteLine(logicalDiskPath);
                    Trace.WriteLine(partitionPath);

                    Match logicalDiskNameMatch = _logicalDiskNameRegex.Match(logicalDiskPath);

                    if (logicalDiskNameMatch.Success)
                    {
                        Match partitionDiskIndexMatch = _partitionDiskIndexRegex.Match(partitionPath);

                        if (partitionDiskIndexMatch.Success)
                        {
                            try
                            {
                                driveName = logicalDiskNameMatch.Value;

                                physicalHardDisk = partitionDiskIndexMatch.Value;
                                driveFileSystem = driveInfos[driveName].DriveFormat;
                                lazySuccess = true;
                            }
                            catch (Exception ex)
                            {
                                Trace.WriteLine(ex.ToString());
                            }
                        }
                    }

                    if (!lazySuccess)
                    {
                        // old good code but less performance, to be on the safe side if lazy method fails.
                        ManagementObject logicalDiskObject = new ManagementObject(logicalDiskPath);
                        ManagementObject partitionObject = new ManagementObject(partitionPath);

                        driveName = (string)logicalDiskObject["Name"];
                        driveFileSystem = (string)logicalDiskObject["FileSystem"];
                        physicalHardDisk = partitionObject["DiskIndex"].ToString();
                    }

                    Dictionary<string, string> hardDiskDrives;

                    if (!results.TryGetValue(physicalHardDisk, out hardDiskDrives))
                    {
                        hardDiskDrives = new Dictionary<string, string>();
                        results.Add(physicalHardDisk, hardDiskDrives);
                    }

                    hardDiskDrives.Add(driveName, driveFileSystem);
                }
            }
        }

        return ToArray(results.Values);
    }

【讨论】:

    【解决方案3】:

    我发现最好的方法是从 4 个类中的每一个中获取完整数据,然后加入 LINQ 以尽量减少对 WMI 服务的影响(因为它在负载下很慢)。

    一开始你可能认为这听起来很可怕,但请测试一下,看看我在说什么。

    【讨论】:

      【解决方案4】:

      请参阅this article(带有代码示例)关于 GetLogicalDrives、GetLogicalDriveStrings、GetDriveType 和 GetVolumeInformation

      要查找物理驱动器,你可以使用FindFirstVolumeFindNextVolume(我得到“\.\Device{uiid}”。结合GetVolumePathNamesForVolumeNameW来获取相关的驱动器号。然后你可以得到你的信息想要使用上述 API。 如果您需要分区/磁盘编号,请参阅DeviceIoControl 以获取该信息

      我认为您需要代码中 results 中的内容。

      【讨论】:

      • 谢谢,但这并没有多大帮助。是否有类似的功能可以帮助在逻辑驱动器与其物理磁盘之间进行映射?
      猜你喜欢
      • 2012-04-06
      • 2011-01-03
      • 2016-11-06
      • 2019-06-15
      • 2013-06-11
      • 2010-12-31
      • 2012-01-25
      • 2021-12-15
      • 2011-02-13
      相关资源
      最近更新 更多