2009-11-20 3 views
3

J'ai écrit un code en C# qui mappe les disques logiques à leurs disques physiques, en utilisant WMI (System.Management). Le code fonctionne parfaitement, mais lent comme l'enfer. Dans ma machine (Windows 7 x64, Dual-Core avec 3 Go de RAM), il fonctionne au moins 1 seconde. 1 seconde est trop lent pour moi, même 0,1 est plus que suffisant pour accomplir. Je suis plus que douloureux que cette fonctionnalité peut être fait en moins de 0,1 seconde.WMI Mauvaise performance

Y at-il des fonctions Win32API qui peuvent aider?

D'autres suggestions?

ceci est mon code à ce jour:

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

pouvez-vous s'il vous plaît poster votre définition des options? –

+0

Désolé, mon mauvais, j'ai corrigé le code ci-dessus. Je n'utilise pas d'options à l'origine, j'ai juste essayé d'augmenter les performances, mais cela n'aide pas. – DxCK

Répondre

1

Eh bien, voici un code qui fonctionne au moins sur mon système (d'un point de vue objectif) plus rapidement et donne les mêmes résultats. Comme la liste des lecteurs ne changera probablement pas à chaque seconde, je ne sais pas pourquoi vous vous en souciez vraiment, mais de toute façon, voyez si cela vous rend plus heureux. Vous pouvez accélérer légèrement en supprimant le code se Win32_DiskDrive au début, bonne chance le faire courir dans 0.1s si :)

 
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; 
    } 
} 
+0

Merci beaucoup, vous m'avez beaucoup aidé! :-) Votre code fonctionne sur ma machine x4 fois plus vite que le mien. De plus, j'ai réussi à améliorer les performances en fonction de votre idée de Win32_LogicalDiskToPartition, et maintenant il fonctionne x23 fois plus vite que ma première version. :RÉ – DxCK

0

voir this article (avec exemple de code) à propos GetLogicalDrives, GetLogicalDriveStrings, GetDriveType et GetVolumeInformation

Pour trouver des disques physiques, vous pouvez utiliser FindFirstVolume et FindNextVolume (J'obtiens "\. \ Device {uiid}" Combiné avec GetVolumePathNamesForVolumeNameW pour obtenir la lettre de lecteur associée.Vous pouvez obtenir l'information que vous voulez avec les API mentionnées ci-dessus Si vous avez besoin de numéros de partition/disque, voir DeviceIoControl pour obtenir cette information

Je pensais que vous aviez besoin de ce qui est results dans votre code.

+0

Merci, mais cela n'aide pas beaucoup. Existe-t-il des fonctions similaires qui peuvent aider à mapper entre les unités logiques et leurs disques physiques? – DxCK

1

Ceci est mon code final, x23 plus vite que la première version, basée sur l'idée de Tyranides utiliser 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); 
    } 
1

J'ai trouvé que la meilleure voie est d'obtenir les données complètes de chacune des 4 classes, puis faites votre joindre à LINQ pour minimiser l'impact sur le service WMI (comme il est lent sous charge). Comme d'abord, vous pourriez penser que cela semble horrible, mais le tester pour voir de quoi je parle.