Wyobraź sobie kod:
public class obj
{
// elided
}
public static Dictionary<string, obj> dict = new Dictionary<string, obj>();
Metoda 1
public static obj FromDict1(string name)
{
if (dict.ContainsKey(name))
{
return dict[name];
}
return null;
}
Metoda 2
public static obj FromDict2(string name)
{
try
{
return dict[name];
}
catch (KeyNotFoundException)
{
return null;
}
}
Byłem ciekawy, czy jest różnica w wydajności tych 2 funkcji, ponieważ pierwsza POWINNA BYĆ wolniejsza niż druga - biorąc pod uwagę, że musi ona dwukrotnie sprawdzić, czy słownik zawiera wartość, podczas gdy druga funkcja musi mieć dostęp tylko do słownika raz, ale WOW, w rzeczywistości jest odwrotnie:
Pętla dla 1 000 000 wartości (przy 100 000 istniejących i 900 000 nieistniejących):
pierwsza funkcja: 306 milisekund
druga funkcja: 20483 milisekund
Dlaczego?
EDYCJA: Jak można zauważyć w komentarzach pod tym pytaniem, wydajność drugiej funkcji jest w rzeczywistości nieco lepsza niż pierwsza w przypadku, gdy nie ma 0 kluczy. Ale gdy jest co najmniej 1 lub więcej nieistniejących kluczy, wydajność drugiego z nich gwałtownie spada.
źródło
ContainsKey
oczekuje sięO(1)
...O(1)
wyszukiwanie w słowniku ... Zwłaszcza, że wykonywanie dwóchO(1)
operacji jest wciąż asymptotycznieO(1)
.Odpowiedzi:
Z jednej strony zgłaszanie wyjątków jest z natury drogie , ponieważ stos musi zostać rozwinięty itp.
Z drugiej strony dostęp do wartości w słowniku według jego klucza jest tani, ponieważ jest to szybka operacja O (1).
BTW: Prawidłowym sposobem na to jest użycie
TryGetValue
Umożliwia to dostęp do słownika tylko raz zamiast dwa razy.
Jeśli naprawdę chcesz po prostu wrócić,
null
jeśli klucz nie istnieje, powyższy kod można dodatkowo uprościć:To działa, ponieważ
TryGetValue
ustawiaitem
się,null
jeśli niename
istnieje żaden klucz .źródło
Słowniki są specjalnie zaprojektowane do przeprowadzania superszybkich wyszukiwań kluczy. Są one implementowane jako tabele skrótów i im więcej wpisów, tym szybciej są względem innych metod. Używanie mechanizmu wyjątków powinno się odbywać tylko wtedy, gdy metoda nie wykonała tego, do czego została zaprojektowana, ponieważ jest to duży zestaw obiektów, który zapewnia wiele funkcji obsługi błędów. Raz zbudowałem całą klasę biblioteki ze wszystkim otoczonym przez try catch catch i byłem przerażony, widząc wyniki debugowania, które zawierały osobną linię dla każdego z ponad 600 wyjątków!
źródło