2009-12-13 14 views
18

Oto ciekawość, którą badałem. Klasa .NET Dictionary wykonuje absurdalnie szybko w porównaniu do STL unordered_map w teście, który sprawdzam, i nie mogę zrozumieć dlaczego.Hash table szybciej w C# niż C++?

(0,5 sekundy w porównaniu z 4 sekund na moim komputerze) (.NET 3.5 SP1 vs Visual Studio STL 2008 Express SP1'S)

Z drugiej strony, jeśli zaimplementować własną tabeli mieszania w C# i C++ , wersja C++ jest około dwa razy szybsza niż C#, co jest w porządku, ponieważ wzmacnia mój zdrowy rozsądek, że natywny kod maszynowy jest czasami szybszy. (Zdarzało się, że mówiłem "czasami".) Ja będąc tą samą osobą w obu językach, zastanawiam się, jakie sztuczki był koder C# od Microsoftu, który mógł odtwarzać, że koder C++ od Microsoftu nie był? Mam problem z wyobrażeniem sobie, w jaki sposób kompilator może sam odtwarzać takie sztuczki, starając się zoptymalizować to, co powinno mieć na celu arbitralne wywoływanie funkcji.

To prosty test, przechowywanie i pobieranie liczb całkowitych.

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

Czy wersja w języku C++ wpisana jest jako słownik ? –

+7

Macierzysty kod maszynowy jest szybszy niż co? Jak myślisz, jak działa C#? –

+1

Jak mierzyć wydajność? – stefanB

Odpowiedz

10

obie wersje nie są równoważne, twój budują iterator w każdym przejściu dysku C++ pętli while. to wymaga czasu procesora i wyrzuca wyniki.

+0

Uzgodniono - spróbuj zastąpić "dict.insert (pair (i, i * 7));" z "dict [i] = i * 7;" Jeden mniejszy poziom gook. –

+0

To i używają operatora tablic w wersji C# i find() w wersji C++. – Glen

+0

@Glen: "operator tablic" jest syntaktyczną wygodą, która wywołuje metodę 'FindEntry'. Nie ma przewagi prędkości. –

2

Na poziomie kodu wystąpią pewne różnice: fakt, że nieuporządkowana mapa przyjmuje parę, wymusza konstrukcję takiego obiektu, gdy C# może być szybszy po podaniu dwóch parametrów w oknie Dodaj.

Innym celem jest implementacja samych haseł: implementacja funkcji haszowania lub sposób radzenia sobie z kolizjami spowoduje różne wzorce wydajności.

Rzucanie wyrównania i buforowania, przyjazność JIT dla niektórych algorytmów i porównywanie dwóch różnych implementacji w dwóch różnych językach staje się bardzo trudne, a jedyną rzeczą, którą można porównać, jest konkretne zadanie pod ręką. Wypróbuj mniej lub więcej elementów lub spróbuj uzyskać dostęp do elementów losowo zamiast kolejno, a możesz zobaczyć bardzo różne wyniki.

5

Mierzysz koszt zarządzania pamięcią jawną. Więcej statystyk jest dostępnych here. To jest relevant too. i Chris Sells' attempt, aby dodać deterministyczny finalizacji do CLR jest godne uwagi.

+2

+1 - dla świetnych linków. –

Powiązane problemy