2009-04-03 20 views
41

Cuando se utiliza un Guid como índice para un Dictionary, ¿es mejor utilizar el objeto Guid, o la representación de cadena del Guid?Rendimiento - utilizando el objeto Guid o la cadena Guid como clave

Acabo de refactorizar algún código que estaba usando una cadena para usar el objeto, porque había llamadas new Guid() por todas partes. Pero eso me dejó preguntándome cuáles podrían ser los problemas de rendimiento. (Las colecciones son bastante pequeñas, pero se iteran muchas veces).

Respuesta

68

El Guid debe ser más rápido, ya que la comparación es más simple: unos pocos bytes directos. La cadena implica una desreferencia y mucho más trabajo.

Por supuesto - se podía perfil ;-P

Evidencia:

Searching for 7f9b349f-f36f-94de-ad96-04279ddf6ecf 
As guid: 466; -1018643328 
As string: 512; -1018643328 
Searching for 870ba465-08f2-c872-cfc9-b3cc1ffa09de 
As guid: 470; 1047183104 
As string: 589; 1047183104 
Searching for d2376f8a-b8c9-4633-ee8e-9679bb30f918 
As guid: 423; 1841649088 
As string: 493; 1841649088 
Searching for 599889e8-d5fd-3618-4c4f-cb620e6f81bb 
As guid: 488; -589561792 
As string: 493; -589561792 
Searching for fb64821e-c541-45f4-0fd6-1c772189dadf 
As guid: 450; 1389733504 
As string: 511; 1389733504 
Searching for 798b9fe5-ba15-2753-357a-7637161ee48a 
As guid: 415; 779298176 
As string: 504; 779298176 
Searching for 12ba292e-8e59-e5d0-7d04-e811a237dc21 
As guid: 457; 558250944 
As string: 564; 558250944 
Searching for 05b3ce14-dfbf-4d3a-1503-ced515decb81 
As guid: 413; 1658205056 
As string: 504; 1658205056 
Searching for 8db4a556-0a65-d8cb-4d0d-0104245d18b8 
As guid: 415; 696231936 
As string: 506; 696231936 
Searching for c49cf80c-5537-fba5-eebd-8ad21bba09c4 
As guid: 459; 2100976384 
As string: 557; 2100976384 

basado en:

using System; 
using System.Collections.Generic; 
using System.Diagnostics; 
using System.Linq; 
static class Program 
{ 

    static void Main() 
    { 
     Random rand = new Random(123456); 
     int COUNT = 1000; 
     Dictionary<Guid, int> guids = new Dictionary<Guid, int>(COUNT); 
     Dictionary<string, int> strings = new Dictionary<string, int>(
      COUNT, StringComparer.Ordinal); 

     byte[] buffer = new byte[16]; 
     for (int i = 0; i < COUNT; i++) 
     { 
      rand.NextBytes(buffer); 
      Guid guid = new Guid(buffer); 
      int val = rand.Next(); 
      guids.Add(guid, val); 
      strings.Add(guid.ToString(), val); 
     } 

     for(int i = 0 ; i < 10 ; i++) { 
      int index = rand.Next(COUNT); 
      Guid guid = guids.Keys.Skip(index).First(); 
      Console.WriteLine("Searching for " + guid); 
      int chk = 0; 
      const int LOOP = 5000000; 
      Stopwatch watch = Stopwatch.StartNew(); 
      for (int j = 0; j < LOOP; j++) 
      { 
       chk += guids[guid]; 
      } 
      watch.Stop(); 
      Console.WriteLine("As guid: " + watch.ElapsedMilliseconds 
        + "; " + chk); 
      string key = guid.ToString(); 
      chk = 0; 
      watch = Stopwatch.StartNew(); 
      for (int j = 0; j < LOOP; j++) 
      { 
       chk += strings[key]; 
      } 
      watch.Stop(); 
      Console.WriteLine("As string: " + watch.ElapsedMilliseconds 
        + "; " + chk); 
     } 
     Console.ReadLine(); 

    } 
} 
+5

Oh, no lo harás por mí?;) – Benjol

+1

¡Guau, lo hiciste! ¡La respuesta es suya, señor! – Benjol

+0

Servicio con una sonrisa ;-p –

2

Las colecciones son bastante pequeñas, pero que reciben una gran cantidad de iterados veces

Si está iterando, no hay una clave para las comparaciones de claves. Si está agregando/modificando o buscando por clave, las claves se compararán con hash y hash; solo si los hash son iguales se compararán las claves.

Por lo tanto, a menos que realice muchas operaciones basadas en claves en diccionarios enormes con muchas colisiones hash, la velocidad de la clave para las comparaciones clave no será un factor importante.

+0

Sí, malas palabras de mi parte. ¡No tiene mucho sentido tener un diccionario si no hay búsquedas! – Benjol

+0

Un diccionario asegura que las claves son únicas y la inserción O (log n); esto puede ser muy útil incluso si solo vas a iterar. – Richard

+0

(vea la respuesta a su comentario en mi publicación) –

1

Lo primero que pensé fue que los objetos Guid son más rápidos, pero si obtiene una entrada como cadena y tiene que buscarla en una pequeña colección (hashset) de GUID (que no cambian a menudo), podría ser más rápido para almacenarlos como cadenas, debido a que:

  • para buscar una cadena en un GUID-diccionario, hay que analizar la cadena (incluyendo la comprobación de errores, etc.), crear la estructura Guid, obtener el código hash , haga la búsqueda hash y una comparación final de los bytes GUID.

  • Para buscar una cadena en un String-Dictionary, debe compilar el hash de la cadena (posiblemente más rápido que construir la estructura Guid), buscar el hash y hacer una comparación de cadenas. Si, por ejemplo, espera que muchos GUID no estén en las colecciones, la comparación de hash fallará a menudo y ni siquiera tendrá que hacer la comparación de cadenas (lo cual lleva un poco más de tiempo que la comparación GUID del punto 1 anterior)

Si ya tiene Guid-estructuras como entrada (por ejemplo, porque usted hizo algo de validez de comprobación en las cadenas de entrada) por supuesto que es mucho mejor para reutilizarlos como índice en el diccionario.

PERO: Desde el punto de vista de la claridad de diseño (que es mucho más importante que el rendimiento en el 99% de todo el código) se debe utilizar Guid estructuras y sólo cambiar eso, si de verdad se encuentra con problemas de rendimiento (y perfiles muestra que obtiene una ventaja de la solución de cadena).