WMI 性能不佳

发布于 2024-08-11 09:43:10 字数 1820 浏览 6 评论 0原文

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

I wrote a code in C# that maps logical drives to their physical disks, using WMI (System.Management).
The code working perfectly, but slow like hell.
In my machine (Windows 7 x64, Dual-Core with 3 GB RAM) it runs as least 1 second.
1 second is too slow for me, even 0.1 is more than enough to accomplish.
I more than sore that this functionallity can be done in less than 0.1 second.

Is there any Win32API functions that can help?

Any other suggestions?

this is my code so far:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

屌丝范 2024-08-18 09:43:10

好吧,这里有一些代码至少在我的系统上运行得更快(从客观的角度来看)并给出相同的结果。由于驱动器列表几乎不可能每秒改变,我不确定为什么你真的这么关心,但无论如何,看看这是否会让你更快乐。您可以通过删除开始时获取 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;
    }
}

Well here is some code which at least on my system runs (from an objective point of view) quicker and gives the same results. As the list of drives is barely likely to change on a second by second basis I am not sure why you really care so much, but anyway, see if this makes you happier. You can speed it slightly by removing the code getting Win32_DiskDrive at the start, good luck making it run in 0.1s though :)

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;
    }
}
裂开嘴轻声笑有多痛 2024-08-18 09:43:10

这是我的最终代码,比第一个版本快 23 倍,基于使用 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);
    }

This is my final code, x23 faster than the first version, based on tyranid idea to use 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);
    }
高冷爸爸 2024-08-18 09:43:10

我发现最好的途径是从 4 个类中的每一个获取完整数据,然后使用 LINQ 进行连接,以尽量减少对 WMI 服务的影响(因为它在负载下速度很慢)。

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

I have found that the best route is to get the full data from each of the 4 classes and then do your joining with LINQ to minimize the impact on the WMI service (as it is slow under load).

As first you might think that sounds horrible, but test it out to see what I am talking about.

再浓的妆也掩不了殇 2024-08-18 09:43:10

请参阅有关 GetLogicalDrives、GetLogicalDriveStrings、GetDriveType 的这篇文章(包含代码示例)和 GetVolumeInformation

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

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

see this article (with code sample) about GetLogicalDrives, GetLogicalDriveStrings, GetDriveType, and GetVolumeInformation

To find physical drives, you can use FindFirstVolumeand FindNextVolume (I get "\.\Device{uiid}". Combined with GetVolumePathNamesForVolumeNameW to get the associated drive letter. Then you can get the info you want with above mentioned APIs.
If you need partition/disk numbers see DeviceIoControl to get that info

I thought you needed what is in results in your code.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文