2010-01-22 11 views
12

quale sarebbe più veloce?Quanto è costoso un cast GUID e confronto rispetto a un confronto di stringhe

bool same=(Guid)Identifier==id; 

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

non è abbastanza facile da testare? –

+3

simile (ma non la stessa) domanda qui http://stackoverflow.com/questions/713109/performance-using-guid-object-or-guid-string-as-key –

+2

Quando, mai, sarebbe importante? Sembra un caso di micro-ottimizzazione, che dovrebbe essere evitato a tutti i costi. Ricorda, prima fallo funzionare, che (se necessario) rendilo più veloce. –

risposta

26

Ho usato questo codice:

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

e ottenuto questo risultato per diversi valori (scenario migliore):

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! 

E questo risultato per lo stesso valore (scenario peggiore)

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

questa è la migliore risposta in quanto mostra effettivamente un punto di riferimento ... –

+1

Il benchmark esce dal confronto sul byte 1 che è lo sforzo migliore. Se si confrontano ancora più byte, i tempi potrebbero differire ancora di più. Ma la differenza di tempo non è enorme come pretendi, dato che hai incluso .ToString() nel ciclo. string a = victim.ToString(); string b = target.ToString(); per (int i = 0; i <10000000; i ++) { bool uguale = String.Equals (a, b, StringComparison.OrdinalIgnoreCase); } –

+0

@ Mikael, buoni consigli; il tuo suggerimento ha portato un enorme miglioramento sulle prestazioni di string.equals. –

1

Un Guid Guid == utilizzerà il codice come:

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

mentre la stringa di confrontare nel tuo esempio utilizzerà un confronto puntatore non sicuro.

Senza il benchmark, sospetto che il Guid sarà più veloce, ma stiamo parlando di marginale. E hai davvero bisogno di aumentare il numero di confronti con i milioni di dollari per farli avere importanza.

Entrambi i confronti scoppiano in anticipo, ovvero da sinistra a destra, in modo da influire anche sulla velocità. Il confronto delle stringhe ha più controlli prima che avvenga il confronto e un'altra chiamata al metodo.

+0

cosa lo rende più sicuro? – zsharp

+0

ha detto più veloce, non più sicuro, anche se sarei curioso di vedere come un confronto tra stringhe senza distinzione tra maiuscole e minuscole potrebbe utilizzare un confronto tra puntatori. –

+0

La parola chiave "non sicura" non è necessariamente pericolosa da usare, ma ti consente di utilizzare i puntatori di memoria come faresti in C++. Molte funzioni nel framework .Net sono implementate in questo modo. Quindi entrambi i modi sono ugualmente sicuri da usare :) Ho semplicemente riferisco alla funzione effettiva nel quadro - private static int non sicuro CompareOrdinalIgnoreCaseHelper (string Stra stringa STRB) –

1

Un confronto GUID è un memcmp di 16 byte. Non sarà necessariamente peggio di un confronto tra stringhe, ma se ti preoccupi delle prestazioni tanto non dovresti usare il codice gestito.

+0

Il confronto tra stringhe non fa distinzione tra maiuscole e minuscole. Mentre il confronto non dovrebbe essere molto diverso in termini di tempo, non è un confronto byte per byte come sarebbe un Guid. –

+0

Non lo è. Il .Net guid consiste di Int32 + Int16 + Int16 + (byte * 8). E confronta uno contro l'altro fino all'ultimo byte. Significa un massimo di 11 confronti. –

+0

Il codice gestito è in realtà piuttosto veloce - circa il 25-50% più lento di C++ l'ultima volta che ho controllato, circa lo stesso di Java ... confronta quello con l'8.000% più lento per Python/Ruby e il 50.000% più lento per PHP ... –

10

Nel mio test eseguendo un confronto UUID-UUID diretto confronto VS String-String, il confronto UUID richiede circa 1/4 del tempo come confronto di String.

Tuttavia, il casting di String-> UUID è costoso. Molto più costoso della conversione UUID-> String. Entrambi sono più costosi di entrambi i metodi di confronto.

Quindi: Se due UUID confrontano direttamente gli UUID. Se hai due stringhe, confronta le stringhe direttamente. Se si dispone di una stringa e un UUID, convertire l'UUID in una stringa e confrontare le stringhe.

1

.NET Guid è una struttura a 16 byte che, quando rappresentata come una stringa, verrà formattata in questo modello "xxxxxxxx-xxxx- xxxx-xxxx-xxxxxxxxxxxx "che è di circa 32 caratteri.

Così rappresentato come un GUID ci vorrebbe 16 byte e rappresentato come una stringa ci vorrebbe 32 * 2 = 64 byte.

Quindi GUID.Equals() dovrebbe funzionare meglio.

Anche GUID.Equals (GUID) funzionerebbe meglio di guid1 == guid2 perché non ci sono boxe coinvolti nel primo.

+1

'Guid.Equals (oggetto, oggetto)' così avrai coinvolto un/boxing; per favore, vedi il mio benchmark lassù –

+0

Guid.Equals (Guid) è descritto qui. http://msdn.microsoft.com/en-us/library/asw89aw8.aspx. Sembra che non ci siano boxe coinvolti per questo sovraccarico. – Santhosh

+0

oh scusa, pensavo che stavi parlando della versione statica; ma, comunque, dovrai usare Guid.Equals (oggetto) mentre il punto intero riguarda il casting dall'oggetto –