Alguém sabe a resposta e / ou tem alguma opinião a respeito?
Como as tuplas normalmente não seriam muito grandes, eu presumiria que faria mais sentido usar structs do que classes para elas. O que diz você?
performance
class
struct
.net-4.0
Bent Rasmussen
fonte
fonte
ValueTuple<...>
. Consulte a referência em tipos de tupla C #Respostas:
A Microsoft fez com que todos os tipos de tupla referissem tipos no interesse da simplicidade.
Pessoalmente, acho que isso foi um erro. Tuplas com mais de 4 campos são muito incomuns e devem ser substituídas por uma alternativa mais tipificada de qualquer maneira (como um tipo de registro em F #), portanto, apenas pequenas tuplas são de interesse prático. Meus próprios benchmarks mostraram que tuplas não encaixotadas de até 512 bytes ainda podem ser mais rápidas do que tuplas encaixotadas.
Embora a eficiência da memória seja uma preocupação, acredito que o problema dominante é a sobrecarga do coletor de lixo .NET. A alocação e a coleta são muito caras no .NET porque seu coletor de lixo não foi altamente otimizado (por exemplo, em comparação com o JVM). Além disso, o .NET GC (estação de trabalho) padrão ainda não foi paralelizado. Conseqüentemente, programas paralelos que usam tuplas são interrompidos enquanto todos os núcleos disputam o coletor de lixo compartilhado, destruindo a escalabilidade. Essa não é apenas a preocupação dominante, mas a AFAIK foi completamente negligenciada pela Microsoft quando examinou o problema.
Outra preocupação é o envio virtual. Os tipos de referência oferecem suporte a subtipos e, portanto, seus membros são normalmente chamados por meio de envio virtual. Em contraste, os tipos de valor não podem oferecer suporte a subtipos, portanto, a chamada de membro é totalmente inequívoca e pode sempre ser executada como uma chamada de função direta. O envio virtual é extremamente caro no hardware moderno porque a CPU não pode prever onde o contador do programa irá parar. A JVM faz um grande esforço para otimizar o envio virtual, mas o .NET não. No entanto, o .NET oferece uma fuga do envio virtual na forma de tipos de valor. Portanto, representar tuplas como tipos de valor poderia, novamente, ter melhorado dramaticamente o desempenho aqui. Por exemplo, ligando
GetHashCode
em uma tupla de 2, um milhão de vezes leva 0,17s, mas chamá-la em uma estrutura equivalente leva apenas 0,008s, ou seja, o tipo de valor é 20 × mais rápido que o tipo de referência.Uma situação real em que esses problemas de desempenho com tuplas comumente surgem é no uso de tuplas como chaves em dicionários. Na verdade, tropecei neste tópico seguindo um link da questão Stack Overflow F # executa meu algoritmo mais lento do que Python! onde o programa F # do autor acabou sendo mais lento do que seu Python precisamente porque ele estava usando tuplas encaixotadas. Desembalar manualmente usando um
struct
tipo escrito à mão torna seu programa F # várias vezes mais rápido e mais rápido do que Python. Esses problemas nunca teriam surgido se as tuplas fossem representadas por tipos de valor e não por tipos de referência para começar ...fonte
Tuple<_,...,_>
tipos poderiam ter sido lacrados, caso em que nenhum envio virtual seria necessário, apesar de serem tipos de referência. Estou mais curioso para saber por que eles não são selados do que por que são tipos de referência.A razão é mais provável porque apenas as tuplas menores fariam sentido como tipos de valor, uma vez que teriam uma pequena área de cobertura de memória. As tuplas maiores (ou seja, aquelas com mais propriedades) sofreriam de fato no desempenho, pois seriam maiores que 16 bytes.
Em vez de algumas tuplas serem tipos de valor e outras, tipos de referência e forçar os desenvolvedores a saber quais são quais, imagino que o pessoal da Microsoft pensasse que torná-los todos os tipos de referência era mais simples.
Ah, suspeitas confirmadas! Consulte Construindo Tupla :
fonte
Se os tipos .NET System.Tuple <...> fossem definidos como estruturas, eles não seriam escalonáveis. Por exemplo, uma tupla ternária de inteiros longos atualmente é dimensionada da seguinte maneira:
Se a tupla ternária fosse definida como uma estrutura, o resultado seria o seguinte (com base em um exemplo de teste que implementei):
Como as tuplas têm suporte de sintaxe embutido no F # e são usadas com extrema freqüência nesta linguagem, as tuplas "struct" colocariam os programadores em F # em risco de escrever programas ineficientes sem nem mesmo estarem cientes disso. Isso aconteceria tão facilmente:
Na minha opinião, tuplas "struct" causariam uma alta probabilidade de criar ineficiências significativas na programação diária. Por outro lado, as tuplas de "classe" existentes atualmente também causam certas ineficiências, conforme mencionado por @Jon. No entanto, acho que o produto da "probabilidade de ocorrência" vezes "dano potencial" seria muito maior com structs do que atualmente com classes. Portanto, a implementação atual é o mal menor.
Idealmente, haveria tuplas de "classe" e tuplas de "estrutura", ambas com suporte sintático em F #!
Editar (07-10-2017)
As tuplas estruturais agora são totalmente suportadas da seguinte maneira:
fonte
ref
ou não goste do fato de que as chamadas "structs imutáveis" não combinem, especialmente quando encaixadas. É uma pena. .Net nunca implementou o conceito de passagem de parâmetros por um executávelconst ref
, já que em muitos casos essa semântica é o que realmente é necessário.Dictionary
, por exemplo, aqui: stackoverflow.com/questions/5850243 /…Para 2 tuplas, você ainda pode usar o KeyValuePair <TKey, TValue> de versões anteriores do Common Type System. É um tipo de valor.
Um pequeno esclarecimento para o artigo de Matt Ellis seria que a diferença na semântica de uso entre os tipos de referência e de valor é apenas "leve" quando a imutabilidade está em vigor (o que, é claro, seria o caso aqui). No entanto, acho que teria sido melhor no projeto BCL não introduzir a confusão de ter Tuple passando para um tipo de referência em algum limiar.
fonte
Não sei mas se você já usou F # Tuplas fazem parte da linguagem. Se eu fizesse um .dll e retornasse um tipo de Tuplas, seria bom ter um tipo para colocá-lo. Suspeito agora que o F # faz parte da linguagem (.Net 4) algumas modificações no CLR foram feitas para acomodar algumas estruturas comuns em F #
De http://en.wikibooks.org/wiki/F_Sharp_Programming/Tuples_and_Records
fonte