Представьте себе код:
public class obj
{
// elided
}
public static Dictionary<string, obj> dict = new Dictionary<string, obj>();
Способ 1
public static obj FromDict1(string name)
{
if (dict.ContainsKey(name))
{
return dict[name];
}
return null;
}
Способ 2
public static obj FromDict2(string name)
{
try
{
return dict[name];
}
catch (KeyNotFoundException)
{
return null;
}
}
Мне было любопытно, если есть разница в производительности этих двух функций, потому что первая ДОЛЖНА быть МЕНЬШЕ, чем вторая - учитывая, что необходимо дважды проверить, содержит ли словарь значение, в то время как второй функции нужен только доступ к словарю один раз но ВАУ, на самом деле все наоборот
Цикл для 1 000 000 значений (с 100 000 существующих и 900 000 несуществующих):
первая функция: 306 миллисекунд
вторая функция: 20483 миллисекунды
Это почему?
РЕДАКТИРОВАТЬ: Как вы можете заметить в комментариях ниже этого вопроса, производительность второй функции на самом деле немного лучше, чем первая в случае, если есть 0 несуществующих клавиш. Но при наличии как минимум 1 или более несуществующих ключей производительность второго быстро снижается.
источник
ContainsKey
как ожидаетсяO(1)
...O(1)
в словаре ... Особенно потому, что выполнение двухO(1)
операций все еще асимптотическиO(1)
.Ответы:
С одной стороны, выбрасывать исключения по своей природе дорого , потому что стек должен быть размотан и т. Д.
С другой стороны, доступ к значению в словаре по его ключу дешев, потому что это быстрая операция O (1).
Кстати: правильный способ сделать это - использовать
TryGetValue
Это получает доступ к словарю только один раз вместо двух.
Если вы действительно хотите просто вернуть,
null
если ключ не существует, приведенный выше код может быть упрощен далее:Это работает, потому что
TryGetValue
наборыitem
дляnull
если ни одна клавиша сname
не существует.источник
Словари специально разработаны для супер-быстрого поиска ключей. Они реализованы в виде хеш-таблиц, и чем больше записей, тем быстрее они по сравнению с другими методами. Предполагается, что использование механизма исключений возможно только в том случае, если ваш метод не смог выполнить то, для чего вы его разработали, поскольку это большой набор объектов, которые предоставляют вам множество функций для обработки ошибок. Однажды я собрал целый класс библиотеки, в котором все было окружено блоками try catch, и я был потрясен, увидев вывод отладки, который содержал отдельную строку для каждого из более чем 600 исключений!
источник