90 votes

Pourquoi le nouveau Tuple de type .Net 4.0 un type de référence (la classe) et non une valeur de type (struct)

Personne ne sait la réponse et/ou ont une oppinion à ce sujet?

Depuis les tuples ne sont normalement pas très grande, je suppose qu'il serait plus judicieux d'utiliser les structures de classes. Qu'en dites-vous?

96voto

Jon Harrop Points 26951

Microsoft fait tout n-uplet types de types de référence dans l'intérêt de la simplicité.

Personnellement, je pense que c'était une erreur. Les Tuples avec plus de 4 champs sont très rare et doit être remplacé par un plus typeful alternative de toute façon (comme un type d'enregistrement en F#) donc seulement de petites tuples sont d'intérêt pratique. Mes propres critères d'évaluation ont montré que unboxed tuples jusqu'à 512 octets pourrait être encore plus rapide que la boîte de n-uplets.

Bien que l'efficacité de mémoire est une préoccupation, je crois que le principal problème est la surcharge de la .NET garbage collector. De répartition et de recouvrement sont très coûteux .NET parce que son garbage collector n'a pas été très fortement optimisé (par exemple, par rapport à la JVM). En outre, la valeur par défaut .NET GC (poste de travail) n'a pas encore été parallélisée. Par conséquent, les programmes parallèles que l'utilisation des n-uplets arrêterait que tous les cœurs de composer pour le partage de garbage collector, détruisant l'évolutivité. Ce n'est pas seulement la préoccupation dominante, mais, autant que je sache, a été complètement négligée par Microsoft lors de l'examen de ce problème.

Une autre préoccupation est virtuel de l'expédition. De référence de la prise en charge des types de sous-types et, par conséquent, leurs membres sont généralement invoquée via le virtuel de l'expédition. En revanche, les types de valeur ne peut pas en charge les sous-types, afin que l'invocation est totalement dépourvu d'ambiguïté et peut toujours être effectuée en direct de l'appel de fonction. Virtuel, l'expédition est très coûteux sur le matériel moderne, car le PROCESSEUR ne peut pas prédire où le compteur de programme. La JVM va de grands efforts pour optimiser virtuel expédition, mais .NET ne fonctionne pas. Cependant, .NET ne permettent de s'évader de virtuel envoi sous la forme de types de valeur. Afin représentant les tuples de la valeur des types, de nouveau, ont considérablement amélioré les performances ici. Par exemple, en appelant GetHashCode sur un 2-tuple d'un million de fois prend 0,17 s, mais de l'appeler sur un équivalent struct prend seulement 0.008 s, c'est à dire le type de valeur est 20 fois plus rapide que le type de référence.

Une situation réelle où ces problèmes de performances avec les tuples souvent se pose est de l'utilisation des n-uplets comme clés dans les dictionnaires. En fait je suis tombé sur ce fil par un lien à partir de la Pile de Débordement de la question F# exécute mon algorithme plus lent que le Python! où l'auteur F# programme s'est avéré être plus lent que son Python, précisément parce qu'il a été à l'aide de boîte de n-uplets. Manuellement unboxing à l'aide d'un écrit à la main struct type fait son F# programme plusieurs fois plus rapide, et plus rapide que Python. Ces questions n'aurait jamais été si tuples étaient représentés par des types de valeur et pas les types de référence pour commencer...

45voto

Andrew Hare Points 159332

La raison en est probablement à cause, seul le petit tuples serait logique que les types de valeur étant donné qu'elles ont une faible empreinte mémoire. Le plus grand des n-uplets (c'est à dire ceux avec le plus de propriétés) serait effectivement souffrir de la performance, car ils seraient plus de 16 octets.

Plutôt que d'avoir certains tuples être des types de valeur et les autres types de référence et de forcer les développeurs à savoir qui sont qui, j'imagine, les gens de chez Microsoft pensé que faire tous les types de référence était plus simple.

Ah, les soupçons confirmés! Veuillez voir la Construction d'un Tuple:

La première décision importante est de savoir si pour traiter les tuples soit comme une référence ou type de valeur. Depuis qu'ils sont immuable tout moment vous souhaitez modifier les valeurs d'un tuple, vous avez pour créer un nouveau. Si ils sont les types de référence, cela signifie qu'il peut beaucoup de déchets générés si vous sont en train de changer des éléments dans un tuple dans une boucle serrée. F# tuples étaient de référence types, mais il y avait un sentiment de l'équipe qu'ils ont pu réaliser un l'amélioration de la performance si deux, et peut-être trois, élément tuples ont été types de valeur à la place. Certaines équipes qui avait créé interne tuples avait utilisé la valeur plutôt que sur les types de référence, parce que leurs scénarios ont été très sensible à la création de lots de la gestion de la objets. Ils ont trouvé que l'utilisation d'une valeur type leur a donné de meilleures performances. Dans notre premier projet de la n-uplet la spécification, nous avons gardé les deux, de trois, et quatre-élément n-uplets d' types de valeur, le reste étant les types de référence. Cependant, lors d'un réunion de conception qui inclus des représentants d'autres langues il a été décidé que ce "split" conception serait source de confusion, en raison de la légèrement différente de la sémantique entre les deux types. La cohérence dans le comportement et la conception ont été déterminés à être de priorité plus élevée que le potentiel de augmente les performances. Sur cette base d'entrée, nous avons modifié la conception de sorte que tous les tuples sont des types référence, bien que nous avons demandé à l'équipe F# à faire certains résultats de l'enquête pour voir si elle a connu une accélération lors de l'utilisation de un type de valeur pour certaines tailles de tuples. Elle avait une bonne façon de tester ce, depuis son compilateur, écrit en F#, était un bon exemple d'un programme plus large que utilisé tuples dans une variété de scénarios. En fin de compte, l'équipe F# a constaté qu'il ne pas obtenir une amélioration de la performance lorsque certains tuples ont été les types de valeur au lieu de types de référence. De ce fait nous sentir mieux à propos de notre décision de utilisation des types de référence pour tuple.

8voto

Marc Sigrist Points 663

Si l' .NET Système.Tuple<...> types ont été définis comme des structures, ils ne seraient pas évolutive. Par exemple, un ternaire n-uplet d'entiers longs actuellement échelles comme suit:

type Tuple3 = System.Tuple<int64, int64, int64>
type Tuple33 = System.Tuple<Tuple3, Tuple3, Tuple3>
sizeof<Tuple3> // Gets 4
sizeof<Tuple33> // Gets 4

Si le ternaire n-uplet a été définie comme une structure, le résultat serait comme suit (sur la base d'un exemple de test j'ai mis en place):

sizeof<Tuple3> // Would get 32
sizeof<Tuple33> // Would get 104

Comme les tuples ont construit en charge de la syntaxe en F#, et ils sont utilisés très souvent dans cette langue, "struct" tuples poserait F#, programmeurs, au risque d'écrire inefficace des programmes sans même en être conscients. Il arriverait-il si facilement:

let t3 = 1L, 2L, 3L
let t33 = t3, t3, t3

À mon avis, "struct" tuples serait la cause d'une forte probabilité de création d'une inefficacité considérable dans le quotidien de la programmation. D'autre part, l'actuelle "classe" tuples aussi causer certaines insuffisances, comme mentionné par @Jon. Cependant, je pense que le produit de "la probabilité d'occurrence du" times "dommages potentiels" serait beaucoup plus élevé avec les structures que c'est le cas actuellement avec les classes. Par conséquent, l'implémentation actuelle est le moindre mal.

Idéalement, il serait à la fois "classe" n-uplets et "struct" tuples, à la fois avec syntaxique de soutien en F#,!

4voto

Glenn Slayden Points 1995

Pour le 2-n-uplets, vous pouvez toujours utiliser le KeyValuePair<TKey,TValue> à partir de versions antérieures du Système de Type Commun. C'est un type de valeur.

Un mineur de clarification à la Matt Ellis article serait que la différence dans l'utilisation de la sémantique entre la référence et de la valeur des types n'est qu'un "léger" lors de l'immutabilité est en effet (ce qui, bien sûr, ce serait le cas ici). Néanmoins, je pense qu'il aurait été mieux dans la BCL de la conception à ne pas introduire de la confusion d'avoir un Tuple de la croix-dessus dans un type de référence à un certain seuil.

0voto

Bionic Cyborg Points 1

Je ne sais pas, mais si vous avez déjà utilisé F# Tuples font partie de la langue. Si j'ai fait une .dll et retourna à un type de Tuples, il est préférable d'avoir un type de mettre en. Je soupçonne maintenant que F# est la partie de la langue.Net 4) certaines modifications à CLR ont été faits pour tenir compte de certaines structures communes en F#

À partir de http://en.wikibooks.org/wiki/F_Sharp_Programming/Tuples_and_Records

let scalarMultiply (s : float) (a, b, c) = (a * s, b * s, c * s);;

val scalarMultiply : float -> float * float * float -> float * float * float

scalarMultiply 5.0 (6.0, 10.0, 20.0);;
val it : float * float * float = (30.0, 50.0, 100.0)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X