2010-01-22 15 views
12

que sería más rápido?¿Qué tan caro es un lanzamiento de GUID y la comparación frente a una comparación de cadena

bool same=(Guid)Identifier==id; 

bool same=String.Equals(string1,string2, StringComparison.OrdinalIgnoreCase); 
+4

no es tan fácil de probar? –

+3

similar (pero no es lo mismo) pregunta aquí http://stackoverflow.com/questions/713109/performance-using-guid-object-or-guid-string-as-key –

+2

¿Cuándo, alguna vez, esto importaría? Esto suena como un caso de micro optimización, que debe evitarse a toda costa. Recuerde, primero haga que funcione, que (si es necesario) hágalo más rápido. –

Respuesta

26

He utilizado este código:

object victim = Guid.Empty; 
Guid target = Guid.NewGuid(); 

Stopwatch sw = new Stopwatch(); 
sw.Start(); 
for (int i = 0; i < 10000000; i++){ 
    bool equal = ((Guid) victim) == target; 
} 
Console.WriteLine("Direct cast : {0}", sw.Elapsed); 

sw.Reset(); sw.Start(); 
for (int i = 0; i < 10000000; i++) 
{ 
    bool equal = Guid.Equals(victim, target); 
} 
Console.WriteLine("Guid.Equals : {0}", sw.Elapsed); 

sw.Reset(); sw.Start(); 
string a = victim.ToString(); // as suggested by Mikael 
string b = target.ToString(); 
for (int i = 0; i < 10000000; i++) 
{ 
    bool equal = String.Equals(a, b, StringComparison.OrdinalIgnoreCase); 
} 
Console.WriteLine("String.Equals : {0}", sw.Elapsed); 

Console.ReadLine(); 

y consiguió este resultado para diferentes valores (mejor de los casos):

object victim = Guid.Empty; 
Guid target = Guid.NewGuid(); 
// Direct cast : 00:00:00.1164198 
// Guid.Equals : 00:00:02.1268147 
// String.Equals : 00:00:00.4129527 // oh my! 

Y este resultado para el mismo valor (peor escenario)

object victim = Guid.Empty; 
Guid target = Guid.Empty; 
// Direct cast : 00:00:00.2793173 
// Guid.Equals : 00:00:03.5625948 
// String.Equals : 00:00:01.7564302 
+1

esta es la mejor respuesta, ya que en realidad muestra un punto de referencia ... –

+1

Su punto de referencia sale de la comparación en el byte 1, que es el mejor esfuerzo. Si compara aún más bytes, los tiempos diferirían aún más. Pero la diferencia de tiempo no es tan grande como usted afirma, ya que ha incluido .ToString() en el ciclo. cadena a = víctima.ToString(); cadena b = target.ToString(); for (int i = 0; i <10000000; i ++) { bool equal = String.Equals (a, b, StringComparison.OrdinalIgnoreCase); } –

+0

@Mikael, buenos consejos; su sugerencia llevó a una gran mejora en el rendimiento de string.equals. –

1

A Guid Guid == utilizará un código como:

public bool Equals(Guid g) 
{ 
if (g._a != this._a) 
{ 
    return false; 
} 
if (g._b != this._b) 
{ 
    return false; 
} 

mientras que la comparación de cadenas en su ejemplo utilizará una comparación puntero inseguro.

Sin evaluación comparativa, sospecho que el Guid será más rápido, pero estamos hablando de marginal. Y realmente necesita elevar el número de comparaciones a los millones para que importe.

Ambas comparaciones saldrán temprano, es decir, de izquierda a derecha, por lo que también afectarán la velocidad. La comparación de cadenas tiene más comprobaciones antes de que ocurra la comparación y una llamada más al método también.

+0

¿Qué lo hace más seguro? – zsharp

+0

dijo más rápido, no más seguro, aunque me gustaría ver cómo una comparación de cadenas que no distingue entre mayúsculas y minúsculas podría usar una comparación de puntero. –

+0

La palabra clave "inseguro" no es necesariamente insegura de usar, pero le permite usar punteros de memoria como lo haría en C++. Muchas funciones en el marco .Net se implementan de esta manera. Por lo que ambas formas son igualmente seguros de usar :) Simplemente refiero a la función real en el marco - private static int insegura CompareOrdinalIgnoreCaseHelper (cadena Stra, cadena strB) –

1

Una comparación de GUID es un memcmp de 16 bytes. No va a ser peor que una comparación de cadenas, pero si te preocupa tanto el rendimiento, no deberías usar código administrado.

+0

Su comparación de cadenas no distingue entre mayúsculas y minúsculas. Si bien la comparación no debería ser muy diferente en términos de tiempo, no es una comparación de byte a byte como lo sería un Guid. –

+0

No lo es. El .Net guid se compone de Int32 + Int16 + Int16 + (bytes * 8). Y compara uno contra el otro hasta el último byte. Lo que significa un máximo de 11 comparaciones. –

+0

El código administrado es en realidad bastante rápido: aproximadamente un 25-50% más lento que C++ lo último que revisé, casi lo mismo que Java ... compare eso con un 8,000% más lento para Python/Ruby, y un 50,000% más lento para PHP ... –

10

En mis pruebas haciendo una comparación UUID-UUID recta VS comparación de String-String, la comparación de UUID toma aproximadamente 1/4 del tiempo como la comparación de Cadena.

Sin embargo, la conversión de String-> UUID es costosa. Mucho más caro que la conversión de UUID-> String. Ambos son más caros que cualquiera de los métodos de comparación.

Entonces: Si tiene dos UUID, compare los UUID directamente. Si tienes dos cadenas, compara las cadenas directamente. Si tiene un String y un UUID, convierta el UUID en un String y compare los Strings.

1

.NET Guid es una estructura de 16 bytes que cuando se representa como una cadena se formateará en este patrón "xxxxxxxx-xxxx- xxxx-xxxx-xxxxxxxxxxxx "que tiene unos 32 caracteres.

Representado como un GUID tomaría 16 bytes y representado como una cadena que tomaría 32 * 2 = 64 bytes.

Entonces GUID.Equals() debería funcionar mejor.

También GUID.Equals (GUID) funcionaría mejor que guid1 == guid2 porque no hay boxeo involucrado en el primero.

+1

'Guid.Equals (objeto, objeto)' por lo que tendrá un/boxing involucrado; por favor, vea mi punto de referencia allí –

+0

Guid.Equals (Guid) se describe aquí. http://msdn.microsoft.com/en-us/library/asw89aw8.aspx. Parece que no hay boxeo involucrado para esta sobrecarga. – Santhosh

+0

oh lo siento, pensé que estás hablando de la versión estática; pero, de todos modos, necesitarás usar Guid.Equals (objeto) ya que todo el punto es acerca del lanzamiento desde el objeto –

Cuestiones relacionadas