DEV Community

Cover image for Desempenho - Aprimorando Span com ZLinq
William Santos
William Santos

Posted on

Desempenho - Aprimorando Span com ZLinq

Olá!

Este é mais um post da seção Desempenho e, desta vez, vamos tratar de uma ferramenta muito útil que nos auxilia a lidar com Span<T>: O ZLinq.

Vamos lá!

Motivação

Como sabemos, não é possível escrever expressões Linq sobre spans e, por isso, é comum termos de iterar em coleções acessadas por esse tipo para realizamos operações.

O ZLinq ambiciona mudar esse comportamento!

Por meio de um método que tranforma seu Span<T> em um ValueEnumerable e permite que, em sua superfície, sejam executadas expressões como aquelas do Linq -- digo como aquelas do Linq e não as deste porque as expressões são todas implementadas pela própria biblioteca, que alega ter 99% das implementações do Linq (como os métodos Select, Where e Aggregate por exemplo).

Aqui temos um exemplo do benchmarking realizado para fins de teste desta biblioteca:

[MemoryDiagnoser]
public class ZLinqBenchmark
{
    [Benchmark]
    public int Linq()
    {
        DummyAccount[] dummies = new DummyAccount[1_000];
        for(int i = 0; i < dummies.Length; i++)
            dummies[i] = new (Guid.NewGuid(), i * 100);

        return
        dummies.Where(d => d.Balance > 1_000)
               .Select(d => d.AccountId)
               .Count();
    }

    [Benchmark]
    public int ZLinq()
    {
        Span<DummyAccount> dummies = stackalloc DummyAccount[1_000];
        for (int i = 0; i < dummies.Length; i++)
            dummies[i] = new(Guid.NewGuid(), i * 100m);

        return
        dummies.AsValueEnumerable()
               .Where(d => d.Balance > 1_000)
               .Select(d => d.AccountId)
               .Count();
    }
}
Enter fullscreen mode Exit fullscreen mode

Como podemos observar, não há grandes diferenças entre os usos do Linq e Zlinq, na verdade há apenas duas: o método Linq utiliza um array, enquanto o ZLinq utiliza um Span<T> e; o método ZLinq lança mão do ValueEnumerable.

Essas simples diferenças produziram o seguinte resultado no benchmarking:

Linq vs ZLinq benchmark

Repare nas alocações: é uma economia de 32k por execução. Agora imagine isso no caminho crítico de uma aplicação, como oferece um desempenho superior por conta da necessidade reduzida de acionamentos do Garbage Collector. Impressionante!

Algo interessante aqui: em cenários onde os dois testes utilizem IEnumerable com tipos complexos, e o ZLinq não utilize um Span<T>, alocações passam a ocorrer, como aquelas que ocorrem com o Linq.

Veja:

ZLinq over array benchmark

Além da alocação próxima, o tempo de execução foi um pouco maior. Ter esse conhecimento é interessante para evitar o uso indiscriminado da biblioteca. O ideal é utilizá-la quando há um cenário propício, no caso quando se usa Span<T>.

Conclusão

ZLinq é uma ferramenta que entrega um desempenho ótimo ao lidarmos com Span<T> tendo a necessidade de utilizar expressões Linq.
A biblioteca ainda está em começo de vida, conta com pouco mais de 20k downloads, mas é mantida pelo mesmo criador do MessagePack-CSharp sobre o qual já falamos aqui.
Vale a pena esperar por mais funcionalidades e melhorias com o tempo.

O código do benckmark está, como sempre, disponível no Github. Divirta-se e me diga o que achou.

Gostou do post? Me deixe saber pelos indicadores. Tem dúvidas ou sugestões? Deixe um comentário ou me procure em minhas redes.

Muito obrigado por ler até aqui, e até o próximo post.

Top comments (5)

Collapse
 
jamey_h_77980273155d088d1 profile image
Jamie H

Nice posting, I'd like to talk to you

Collapse
 
wsantosdev profile image
William Santos

Thanks Jamie.
Please feel free to reach out on LinkedIn, we can talk there.

linkedin.com/in/wsantosdev

Collapse
 
jamey_h_77980273155d088d1 profile image
Jamie H

I will contact you on Email

Collapse
 
neiesc profile image
Edinei Cavalcanti

Ótimo parabéns

Collapse
 
wsantosdev profile image
William Santos

Obrigado, Edinei. Espero que o ZLinq te seja útil.
Abraço.