Kiedy lepiej jest używać klasy Tuple niż KeyValuePair?

90

Zwykle KeyValuePair<TKey,TValue>używam tego typu, gdy mam dane związane z parami w tym sensie, że jeden jest kluczem do drugiego. Jeśli dane są niepowiązane, Tuple<T1,T2>typ ma więcej sensu i poszedłbym z tym.

Teraz właśnie przeczytałem ten artykuł o tym, dlaczego ogólnie należy unikać KeyValuePair<TKey,TValue>i preferować Tuple<T1,T2>. Głównym argumentem jest korzyść wydajnościowa Tuple<T1,T2>.

Wydajność zewnętrzna, czy jest jakiś powód, dla którego KVP byłby lepszym wyborem niż Tuple<T1,T2>?

Nick Gotch
źródło
4
A KeyValuePairto klucz i wartość, a Tuple<T1,T2>to tylko para równych wartości. Możesz także zapytać: „dlaczego powinienem używać, List<Class>jeśli mogę użyć Dictionary<A,B>”.
Tim Schmelter
4
Zgadza się, ale w takim przypadku możesz użyć klucza do wyszukania danych. To coś znaczy. W tym przypadku nazwy są tylko semantyką, nic nie znaczą (dla procesora).
Nick Gotch,
1
Krotka nie jest parą równych wartości, ale pewną liczbą równych typów. Może jest to postrzegane jako szukanie dziury w dziobie, ale np. C ma konstrukcję sumującą dla różnych reprezentacji równych wartości. :)
Jonas

Odpowiedzi:

65

Cóż, na przykład typ można uznać za słabo nazwany. Nazwa KeyValuePair powinna reprezentować klucz i wartość. A co, jeśli twoje dwa obiekty nie są tak naprawdę kluczem i wartością, tylko dwiema rzeczami? Gdybym miał zobaczyć metodę lub właściwość, która ma typ KeyValuePair<TKey, TValue>, oczekiwałbym, że wartości KVP będą kluczem i wartością. Tak naprawdę jest to tylko kwestia zakomunikowania intencji i wyjaśnienia go sobie w przyszłości lub innym członkom zespołu. Krotka nie wskazuje na taki rodzaj skojarzenia.

Krotki ułatwiają również dodawanie kolejnej wartości, dzięki czemu jest to trójka (lub trójka, jakkolwiek chcesz ją nazwać). Niektóre języki .NET, takie jak F #, mają również specjalną składnię dotyczącą krotek.

Z punktu widzenia implementacji, Tuplewiele rzeczy KeyValuePairnie robi. Krotki są porównywalne, implementują interfejsy IComparablei IStructuralEquatable, dzięki czemu łatwiej jest porównać dwie krotki.

vcsjones
źródło
1
Przekonałem się na własnej skórze, że możesz umieścić KeyValuePairs w słowniku, ale nigdy nie uzyskasz wyniku.
MKesper,
3
Ponadto nowy język C # 7.0 obsługuje nową, prostszą składnię krotek, dzięki czemu praca z nimi jest znacznie łatwiejsza i wydajniejsza niż KeyValuePairs. visualstudiomagazine.com/articles/2017/01/01/…
Jacob Stamm
1
Ponadto możliwość nazwania parametrów w krotkach ułatwia konsumentowi zrozumienie, do czego mają one służyć. W typie ogólnym, takim jak KVP, nikt nie zgadnie - chyba że gdzieś jest to specjalnie udokumentowane - jaki ma być klucz - tj. Nie jego typ, ale jaka jest rzeczywista rzecz, jak nazwa ustawienia, społeczność numer bezpieczeństwa itp.
rory.ap
40

KeyValuePair jest strukturą i Tuple jest klasą.

To jest główna różnica, która wpływa na sposób kopiowania obiektów, czy to przez odniesienie, czy przez wartości.

i dlatego Tuple<T1,T2>gdy jest przekazywany dookoła, używa tylko "4 bajtów" w 32-bitowym systemie operacyjnym, podczas gdy KeyValuePair<K,V>wymaga więcej w oparciu o "K i V"

W każdym razie porównanie Tuple i KeyValuePair nie jest dobrym pomysłem (nie ma dla mnie sensu), ponieważ oba służą różnym celom.

Sriram Sakthivel
źródło
2
Jak służą innemu celowi? czy mógłbyś to rozwinąć.
OldSchool,
1
@YakRangi keyvaluepair ma być używany jako kontener dla kluczy i wartości w słowniku, w przeciwnym razie nie służy to żadnemu celowi. Z drugiej strony Tuple może służyć do przechowywania razem dowolnie powiązanych członków. Również w Tuple możesz przechowywać wielu członków razem, nie tylko 2.
Sriram Sakthivel
@SriramSakthivel Oznacza to, że odpowiedź na pytanie OP brzmi: nie używaj KVP, chyba że przeglądasz słownik.
Alex Fainshtein
23

Pomimo semantyki wydajność może być ważnym czynnikiem, biorąc pod uwagę obie opcje. Jak wcześniej wspomniano, KeyValuePairjest typem wartości (struct), podczas gdy Tuple<>jest typem referencyjnym (klasą). W związku z tym KeyValuePairalokacja jest przydzielana na stosie, a Tuple<>na stercie, a optymalny wybór jest zwykle określany przez klasyczne argumenty alokacji pamięci stosu względem sterty. . Krótko mówiąc, przestrzeń w stosie jest ograniczona, ale ogólnie ma bardzo szybki dostęp. Pamięć sterty jest znacznie większa, ale jest nieco wolniejsza.

KeyValuePair<T1, T2>może być lepszym wyborem, jeśli zarówno klucz i wartość typy są prymitywy (typy wartości podoba int, bool, double, itd.) lub elemencie małej wielkości. Przy typach prymitywnych na stosie alokacja i zwalnianie przydziałów przebiega błyskawicznie. Może to naprawdę wpłynąć na wydajność, zwłaszcza jako argumenty wywołań metod rekurencyjnych.

Z drugiej strony Tuple<T1, T2>jest prawdopodobnie lepszym wyborem, jeśli jeden z typów referencyjnych T1lub T2są to typy referencyjne (takie jak klasy). A, KeyValuePairktóry zawiera wskaźniki do typów referencyjnych (jako typy klucza lub typy wartości), pokonuje cel, ponieważ obiekty i tak będą musiały być wyszukiwane na stercie.

Oto test porównawczy, który znalazłem online: Tuple vs. KeyValuePair . Jedynym problemem związanym z tym testem porównawczym jest to, że testowali je w KeyValuePair<string, string>porównaniu Tuple<string, string>z stringtypem , a typ jest nietypowym i specjalnym typem w .NET, ponieważ może zachowywać się zarówno jak typ wartości i / lub typ referencyjny w zależności od kontekstu wykonania. Uważam, że KeyValuePair<int, int>byłby wyraźnym zwycięzcą przeciwko Tuple<int, int>. Jednak nawet przy niedociągnięciach wyniki pokazują, że różnice w wydajności mogą być znaczące:

8.23 ns - Allocate Tuple
0.32 ns - Allocate KeyValuePair (25x szybciej!)

1,93 ns - Przekaż krotkę jako argument
2,57 ns - Przekaż KeyValuePair jako argument

1,91 ns - Return Tuple
6.09 ns - Return KeyValuePair

2.79 ns - Załaduj krotkę z listy
4.18 ns - Załaduj KeyValuePair z listy

Sos specjalny
źródło
0

Naprawdę zadajesz złe pytanie właściwym pytaniem jest użycie klasy (krotki) _ lepszej niż struktury (KVP) w takim przypadku odpowiedzią jest to, do czego chcesz ich użyć, a odpowiedź jest podana tutaj Struktury kontra klasy

MikeT
źródło
2
Zadał właściwe pytanie. Pytanie, które jest lepsze dla jakiego użycia, jest wyraźnie implikowane.
Greg
@Greg pytanie brzmi, która jest lepsza czekolada lub napoje gazowane, jednak konkretne pytanie jest bezcelowe i lepiej
ujęte
3
Pytanie defacto brzmi: „Kiedy należy używać krotek i par kluczy?”. To uzasadnione pytanie. Myślę, że utknąłeś na semantyce słowa „lepiej”.
Greg,