WMI表现不佳

时间:2009-11-20 13:44:04

标签: c# .net performance wmi disk

我在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);
        }
    }
}

4 个答案:

答案 0 :(得分:1)

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

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

ManagementClass diskPartMap = null;
ManagementObjectCollection diskPartIns = null;
ManagementClass partLogicalMap = null;
ManagementObjectCollection partLogicalIns = null;

try
{
    using (ManagementClass diskDriveClass = new ManagementClass("Win32_Diskdrive"))
    {
        using (ManagementObjectCollection diskDrives = diskDriveClass.GetInstances())
        {
            foreach (ManagementObject diskDrive in diskDrives)
            {
                results.Add((string)diskDrive["DeviceId"], new Dictionary<string, string>());
            }
        }
    }

    Dictionary<string, ManagementObject> partToDisk = new Dictionary<string, ManagementObject>();
    Dictionary<string, ManagementObject> partToLogical = new Dictionary<string, ManagementObject>();

    diskPartMap = new ManagementClass("Win32_DiskDriveToDiskPartition");
    diskPartIns = diskPartMap.GetInstances();
    foreach (ManagementObject diskDrive in diskPartIns)
    {
        ManagementObject o = new ManagementObject((string)diskDrive["Antecedent"]);
        partToDisk.Add((string)diskDrive["Dependent"], o);
    }

    partLogicalMap = new ManagementClass("Win32_LogicalDiskToPartition");
    partLogicalIns = partLogicalMap.GetInstances();
    foreach (ManagementObject diskDrive in partLogicalIns)
    {
        ManagementObject o = new ManagementObject((string)diskDrive["Dependent"]);
        string s = (string)diskDrive["Antecedent"];

        partToLogical.Add(s, o);
    }

    foreach (KeyValuePair<string, ManagementObject> pair in partToDisk)
    {
        string deviceId = (string)pair.Value["DeviceId"];
        Dictionary<string, string> dict = null;
        if (!results.ContainsKey(deviceId))
        {
            dict = new Dictionary<string, string>();
            results[deviceId] = dict;
        }
        else
        {
            dict = results[deviceId];
        }

        if (partToLogical.ContainsKey(pair.Key))
        {
            ManagementObject o = partToLogical[pair.Key];
            dict.Add((string)o["Name"], (string)o["FileSystem"]);
        }
    }
}
finally
{
    if (diskPartIns != null)
    {
        diskPartIns.Dispose();
        diskPartIns = null;
    }

    if (diskPartMap != null)
    {
        diskPartMap.Dispose();
        diskPartMap = null;
    }

    if (partLogicalIns != null)
    {
        partLogicalIns.Dispose();
        partLogicalIns = null;
    }

    if (partLogicalMap != null)
    {
        partLogicalMap.Dispose();
        partLogicalMap = null;
    }
}

答案 1 :(得分:1)

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

首先你可能认为这听起来很糟糕,但要测试一下,看看我在谈论什么。

答案 2 :(得分:1)

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

    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 :(得分:0)

请参阅this article(包含代码示例),了解GetLogicalDrives,GetLogicalDriveStrings,GetDriveType和GetVolumeInformation

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

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