C# possui dois tipos diferentes para tuplas: ValueTuple e Tuple. O primeiro, ValueTuple, é uma struct e, por isso, por padrão, tem suas instâncias na stack. O segundo, Tuple, é uma classe e, por isso, tem suas instâncias na heap.

Tuple surgiu primeiro. ValueTuple veio depois para permitir ganhos de performance.

Tuple e ValueTuple na memória

Tuple, sendo uma classe (na heap), ocupa mais memória. Por exemplo, se criarmos uma instância de Tuple<float, float>, para representar um Point2, com coordenadas X e Y, este ocupará 16 bytes quando estivermos utilizando uma configuração de 32 bits e 24 bytes quando estivermos utilizando uma configuração de 64 bits.

ValueTuple, sendo uma struct (na stack), é mais limitada e ocupa menos memória. Seguindo o mesmo raciocínio que seguimos anteriormente, uma ValueTuple<float, float>, ocuparia apenas 8 bytes na memória, independente da configuração.

Para saber mais sobre os impactos de escolher classes ou structs, recomendamos a leitura do post que escrevemos sobre esse tema.

Tuple e ValueTuple no cache do processador

Atualmente, quase todos os processadores oferecem múltiplos níveis de caching para tornar o acesso a dados na memória mais rápido. Quanto mais próximo do processador estiver o cache, mais rápido o acesso (o acesso a memória RAM, pelo processador, é, geralmente 200x mais lento que o acesso. ao cache que está mais próximo do processador).

O cache mais próximo do processador costuma ser organizado em “linhas” de 64 bytes cada. Estrategicamente, o processador, ao buscar dados da memória, carrega dados adjacentes por assumir que esses dados serão utilizados na sequência. Se, por exemplo, tivermos arrays de Tuple<float, float> para processar, haverá espaço para quatro objetos no cache do processador quando estivermos rodando em 32 bits e dois quando estivermos rodando em 64 bits. Se estivermos rodando com ValueTuples<float, float>, teremos 8 objetos.

Essa diferença, aparentemente simples, implica em grandes diferenças em tempos de execução, como podemos ver no teste que segue:

using System;
using System.Collections.Generic;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;

namespace Tuples
{
    public class Program
    {
        static void Main()
        {
            BenchmarkRunner.Run<SUT>();
        }
    }

    public class SUT
    {
        public const int NUMBER_OF_TUPLES = 10000000;

        public static readonly List<Tuple<float, float>> SourceOfTuples =
            new List<Tuple<float, float>>(NUMBER_OF_TUPLES);

        public static readonly List<ValueTuple<float, float>> SourceOfValueTuples =
            new List<ValueTuple<float, float>>(NUMBER_OF_TUPLES);


        [GlobalSetup]
        public void GlobalSetup()
        {
            for (var i = 0; i < NUMBER_OF_TUPLES; i++)
            {
                SourceOfTuples.Add(new Tuple<float, float>(i, i));
                SourceOfValueTuples.Add(new ValueTuple<float, float>(i, i));
            }
        }

        [Benchmark]
        public float SumUsingTuples()
        {
            var sum = 0f;
            for (var i = 0; i < NUMBER_OF_TUPLES; i++)
            {
                sum += SourceOfTuples[i].Item1;
            }

            return sum;
        }

        [Benchmark]
        public float SumUsingValueTuples()
        {
            var sum = 0f;
            for (var i = 0; i < NUMBER_OF_TUPLES; i++)
            {
                sum += SourceOfValueTuples[i].Item1;
            }

            return sum;
        }
    }
}

No teste, apenas somamos um dos elementos em duas listas – uma com Tuples e a outra com ValueTuples. Repare que não há qualquer inferência de GC visto que a carga acontece em um Setup e, não surpreendendo, a versão com ValueTuples foi 33% mais rápida.

Tuples vs ValueTuples e o Garbage Collector

Tuples são alocadas na heap, logo, impactam o GC. ValueTuples são alocadas na Stack, logo, não geram pressão sobre o GC a menos que passem por um processo de boxing.

Tuples vs ValueTuples e o .NET

Recentemente, a Microsoft adicionou a capacidade de funções em C# retornarem tuplas. Essas funções, na verdade, estão retornando ValueTuples. Um dos engenheiros responsáveis pela implementação fez uma série de excelentes posts explicando todo o embasamento dessa decisão em seu blog.

Desvantagens de ValueTuples

Todas as restrições conhecidas para structs estão impostas a ValueTuples. Há sempre de se considerar o custo de cópia sempre que um objeto no stack é passado para outro contexto; Não há suporte a multi-threading (sempre há cópia entre as threads, em contrapartida, não é necessário implementar qualquer tipo de gestão de concorrência).

Por enquanto … era isso

Nesse post fizemos uma breve apresentação do tipo ValueTuple e promovemos algumas comparações. Em posts futuros, falaremos mais sobre a decisão da Microsoft de usar structs em outros pontos chaves do framework indicando o que podemos aprender com a gigante de Redmond para melhorar nosso código.

Deixe suas impressões nos comentários.

Compartilhe este insight:

Comentários

Participe deixando seu comentário sobre este artigo a seguir:

Subscribe
Notify of
guest
1 Comentário
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Vinícius Mamoré Caldeira de Oliveira
Vinícius Mamoré Caldeira de Oliveira
3 anos atrás

Muito interessante, obrigado pelo post!

AUTOR

Elemar Júnior
Fundador e CEO da EximiaCo atua como tech trusted advisor ajudando empresas e profissionais a gerar mais resultados através da tecnologia.

NOVOS HORIZONTES PARA O SEU NEGÓCIO

Nosso time está preparado para superar junto com você grandes desafios tecnológicos.

Entre em contato e vamos juntos utilizar a tecnologia do jeito certo para gerar mais resultados.

Insights EximiaCo

Confira os conteúdos de negócios e tecnologia desenvolvidos pelos nossos consultores:

Arquitetura de Dados

Insights de um DBA na análise de um plano de execução

Especialista em performance de Bancos de Dados de larga escala
Arquitetura de Software

Estratégias para modernização do legado

Desenvolvedor .NET/NodeJs e especialista em Kafka com experiência em startups e grandes empresas
Infraestrutura e Nuvem

Migração para a nuvem, mais do que mudança tecnológica, implica em mudança da cultura organizacional

Engenheiro de nuvem, arquiteto de software e especialista em Containers e Devops

Acesse nossos canais

Simplificamos, potencializamos e aceleramos resultados usando a tecnologia do jeito certo

EximiaCo 2022 – Todos os direitos reservados

1
0
Queremos saber a sua opinião, deixe seu comentáriox
()
x

ValueTuple vs Tuple

Para se candidatar nesta turma aberta, preencha o formulário a seguir:

Condição especial de pré-venda: R$ 14.000,00 - contratando a mentoria até até 31/01/2023 e R$ 15.000,00 - contratando a mentoria a partir de 01/02/2023, em até 12x com taxas.

Tenho interesse nessa capacitação

Para solicitar mais informações sobre essa capacitação para a sua empresa, preencha o formulário a seguir:

Tenho interesse em conversar

Se você está querendo gerar resultados através da tecnologia, preencha este formulário que um de nossos consultores entrará em contato com você:

O seu insight foi excluído com sucesso!

O seu insight foi excluído e não está mais disponível.

O seu insight foi salvo com sucesso!

Ele está na fila de espera, aguardando ser revisado para ter sua publicação programada.

Tenho interesse em conversar

Se você está querendo gerar resultados através da tecnologia, preencha este formulário que um de nossos consultores entrará em contato com você:

Tenho interesse nessa solução

Se você está procurando este tipo de solução para o seu negócio, preencha este formulário que um de nossos consultores entrará em contato com você:

Tenho interesse neste serviço

Se você está procurando este tipo de solução para o seu negócio, preencha este formulário que um de nossos consultores entrará em contato com você:

× Precisa de ajuda?