2009-12-13 15 views
18

Ecco una curiosità che ho indagato. La classe .NET Dictionary è incredibilmente veloce rispetto alla STL unordered_map in un test continuo a funzionare e non riesco a capire perché.Tabella hash più veloce in C# rispetto al C++?

(0,5 secondi contro 4 secondi sulla mia macchina) (.NET 3.5 SP1 vs. Visual Studio STL del 2008 Express SP1)

D'altra parte, se implementare la mia tabella hash in C# e C++ , la versione C++ è circa due volte più veloce di quella C#, il che va bene perché rinforza il mio senso comune che il codice macchina nativo sia a volte più veloce. (Vedi. Ho detto "a volte".) Essendo io la stessa persona in entrambe le lingue, mi chiedo quali trucchi sia stato il programmatore C# di Microsoft in grado di riprodurre che il codificatore C++ di Microsoft non lo era? Ho difficoltà a immaginare come un compilatore possa eseguire tali trucchi da solo, passando attraverso il problema di ottimizzare ciò che dovrebbe sembrare essere chiamate di funzione arbitrarie.

È un semplice test, memorizza e recupera numeri interi.

C#:

const int total = (1 << 20); 
int sum = 0; 
Dictionary<int, int> dict = new Dictionary<int, int>(); 
for(int i = 0; i < total; i++) 
{ 
    dict.Add(i, i * 7); 
} 

for(int j = 0; j < (1 << 3); j++) 
{ 
    int i = total; 
    while(i > 0) 
    { 
     i--; 
     sum += dict[i]; 
    } 
} 
Console.WriteLine(sum); 

C++:

const int total = (1 << 20); 
int sum = 0; 
std::tr1::unordered_map<int, int> dict; 
for(int i = 0; i < total; i++) 
{ 
    dict.insert(pair<int, int>(i, i * 7)); 
} 

for(int j = 0; j < (1 << 3); j++) 
{ 
    int i = total; 
    while(i > 0) 
    { 
     i--; 
     std::tr1::unordered_map<int, int>::const_iterator found = 
      dict.find(i); 
     sum += found->second; 
    } 
} 
cout << sum << endl; 
+0

La versione C++ digitata come un dizionario è? –

+7

Il codice macchina nativo è più veloce di cosa? Come pensi che C# vada come? –

+1

come si misura la prestazione? – stefanB

risposta

10

le due versioni non sono equivalenti, il vostro stanno costruendo un iteratore in ogni passaggio del vostro C++ ciclo while. che richiede tempo alla CPU e genera i risultati.

+0

Concordato - prova a sostituire "dict.insert (coppia (i, i * 7));" con "dict [i] = i * 7;" Un livello in meno di ghiottone. –

+0

Questo, e stanno usando l'operatore dell'array nella versione C# e il metodo find() nella versione C++. – Glen

+0

@Glen: "l'operatore di matrice" è una comodità sintattica che chiama il metodo 'FindEntry'. Non ha alcun vantaggio di velocità. –

2

Ci saranno alcune differenze a livello di codice: il fatto che la mappa non ordinata richiede una coppia costringe la costruzione di tale oggetto, quando C# potrebbe essere più veloce con il passaggio di due parametri in Aggiungi.

Un altro punto è l'implementazione degli hashtable stessi: l'implementazione della funzione di hashing, o il modo di affrontare le collisioni, causerà modelli di prestazioni diversi.

L'allineamento e la memorizzazione nella cache, la compatibilità JIT di alcuni algoritmi e il confronto di due diverse implementazioni in due lingue diverse diventano molto difficili e l'unica cosa che è possibile confrontare è l'attività specifica in questione. Prova con meno o più elementi, o prova ad accedere agli elementi casualmente anziché in sequenza, e potresti vedere risultati molto diversi.

5

Si sta misurando il costo della gestione esplicita della memoria. Altre statistiche sono disponibili Questo è relevant too. E il Chris Sells' attempt per aggiungere la finalizzazione deterministica al CLR è notevole.

+2

+1 - per i grandi collegamenti. –

Problemi correlati