Когда лучше использовать Tuple и KeyValuePair?

Обычно я использовал тип KeyValuePair<TKey,TValue> всякий раз, когда у меня есть данные, которые связаны с парой в том смысле, что один из них является ключом к другому. Если данные не связаны, то тип Tuple<T1,T2> имеет больше смысла, и я бы пошел с этим.

Теперь я просто прочитал эту статью о том, почему вообще избегать KeyValuePair<TKey,TValue> и предпочитает Tuple<T1,T2>. Основным аргументом является преимущество производительности Tuple<T1,T2>.

Внешняя производительность, есть ли причина, по которой KVP будет лучшим выбором, чем Tuple<T1,T2>?

Ответ 1

Ну, тип можно назвать плохо названным, для одного. KeyValuePair как именованный должен представлять ключ и значение. Что делать, если ваши два объекта не являются ключом и ценностью, всего две вещи? Если бы я увидел метод или свойство, имеющее тип KeyValuePair<TKey, TValue>, я ожидал бы, что значения KVP будут ключом и значением. Это на самом деле просто вопрос передачи намерения и разъяснения себе в будущем или, возможно, других членов команды. Кортеж не указывает на такую ​​ассоциацию.

Кортежи также упрощают добавление другого значения, делая его 3-кортежем (или триплет, однако вы хотите его называть). Некоторые языки .NET, такие как F #, имеют специальный синтаксис вокруг кортежей.

Для перспективы реализации Tuple делает много вещей KeyValuePair. Кортежи сопоставимы, они реализуют интерфейсы IComparable и IStructuralEquatable, поэтому упрощается сравнение двух кортежей.

Ответ 2

KeyValuePair - это struct и Tuple - класс.

Это основное отличие, которое влияет на то, как объекты копируются по ссылке или значениям.

и, следовательно, Tuple<T1,T2> при передаче только использует "4 байта" в 32-битной ОС, тогда как KeyValuePair<K,V> требует больше основанных на "K и V"

В любом случае сравнение Tuple и KeyValuePair - не очень хорошая идея (для меня это не имеет смысла), так как обе служат для разных целей.

Ответ 3

Несмотря на семантику, производительность может быть важным фактором, поскольку вы рассматриваете оба варианта. Как уже упоминалось ранее, KeyValuePair представляет собой тип значения (struct), тогда как Tuple<> является ссылочным типом (классом). Следовательно, KeyValuePair выделяется в стеке, а Tuple<> выделяется в куче, а оптимальный выбор обычно определяется классическими аргументами Распределение памяти в стеке и ячейке памяти. Короче говоря, пространство стека ограничено, но, как правило, имеет очень быстрый доступ. Память кучи намного больше, но несколько медленнее.

KeyValuePair<T1, T2> может быть лучшим выбором, если оба ключа и значения являются примитивами (типы значений типа int, bool, double и т.д.) или структуры небольшого размера. С примитивными типами в стеке, распределение и освобождение молниеносно. Это может реально повлиять на производительность, особенно в качестве аргументов для рекурсивных вызовов методов.

С другой стороны, Tuple<T1, T2>, вероятно, лучший выбор, если либо T1, либо T2 являются ссылочными типами (например, классы). A KeyValuePair, который содержит указатели на типы ссылок (как типы ключей или значений), порождает цель, так как в любом случае объекты должны быть просмотрены на куче.

В этом тесте, который я нашел в Интернете: Tuple vs. KeyValuePair. Единственная проблема с этим эталоном состоит в том, что они протестировали KeyValuePair<string, string> vs. Tuple<string, string>, а тип string является необычным и особым типом в .NET, поскольку он может вести себя как тип значения и/или ссылочный тип в зависимости от контекста выполнения. Я считаю, что KeyValuePair<int, int> был бы явным победителем против Tuple<int, int>. Однако, несмотря на недостатки, результаты показывают, что различия в производительности могут быть значительными:

8.23 ​​ns - Распределить кортеж
0,32 нс - выделите KeyValuePair (на 25 раз быстрее!)

1.93 ns - передать Tuple в качестве аргумента
2.57 ns - передать KeyValuePair в качестве аргумента

1.91 ns - Возврат кортежа
6.09 ns - Return KeyValuePair

2.79 ns - Загрузка кортежа из списка
4.18 ns - Загрузить KeyValuePair из списка

Ответ 4

В самом деле, задавая неправильный вопрос, правильный вопрос использует класс (кортеж) _ лучше, чем Struct (KVP), и в этом случае ответ - это то, что вы хотите использовать для них, и здесь дается ответ Структуры против классов