Este artigo é um artigo espelhado de tradução automática, por favor clique aqui para ir para o artigo original.

Vista: 6317|Resposta: 3

[Fonte] [Virar]. Otimizações de desempenho da NET - percorra rapidamente coleções de listas

[Copiar link]
Postado em 2022-8-8 20:51:16 | | | |
Breve introdução

System.Collections.Generic.List <T>é uma classe de coleção genérica em .NET, que pode armazenar qualquer tipo de dado devido à sua conveniência e API rica, amplamente usada em nosso dia a dia e pode ser considerada a classe de coleção mais utilizada.

Na escrita de código, muitas vezes precisamos iterar por uma coleção de Listas <T>para obter os elementos nela para algum processamento empresarial. Normalmente, não há muitos elementos dentro de um conjunto e é muito rápido de atravessar. Mas para alguns casos de processamento de big data, estatística, computação em tempo real, etc<T>., como navegar rapidamente pela coleção de listas de dezenas de milhares ou centenas de milhares de dados? É isso que preciso compartilhar com vocês hoje.

Modo de deslocamento

Vamos analisar o desempenho de diferentes métodos de travessia e construir o seguinte benchmark de desempenho, usando diferentes percursos de coleta de ordens de magnitude para ver o desempenho de diferentes métodos. O trecho do código é o seguinte:

Use a instrução foreach

Foreach é a forma mais comum de percorrermos coleções, é uma implementação syntax sugar do padrão iterator, e também é usada como referência para esse período.

Como a instrução foreach é um açúcar sintaxe, o compilador eventualmente chama GetEnumerator() e MoveNext() com um loop while para implementar a funcionalidade. O código compilado é o seguinte:



A implementação do método MoveNext() garantirá que não haja outras threads modificando a coleção na iteração e, se a modificação ocorrer, ela gerará uma exceção InvalidOperationException, e fará uma verificação de overflow para verificar se o índice atual é legítimo, além de precisar atribuir o elemento correspondente ao enumerador. Atributo atual,Então, na verdade, seu desempenho não é o melhor, o trecho de código é assim:



Vamos dar uma olhada em como ele se comporta em diferentes tamanhos de conjunto, e os resultados são os seguintes:



Pode-se ver que, no caso de tamanhos diferentes, a relação de crescimento linear do processo demorado é necessária, mesmo que ele percorra 100w de dados sem qualquer lógica de processamento, leva pelo menos 1s.

Use o método ForEach de Lista

Outra forma comum é usar o List<T>. ForEach(), que permite passar um <T>delegado de Ação, que chamará o delegado de Ação enquanto ele itera pelo <T>elemento.

É um <T>método de implementação interna do List, então pode acessar diretamente arrays privados e evitar verificações de overflow. Em teoria, deveria ser rápido; Mas no nosso cenário existe apenas um método vazio, que pode não se comportar bem com uma chamada totalmente inline para o método foreach. Abaixo está o código-fonte do método ForEach que mostra que ele não possui verificação de overflow, mas ainda mantém a verificação concorrente do número de versão.



Além disso, como é necessário passar um delegado para o método ForEach no código de chamada, ele verificará se o objeto delegado na classe de geração de fechamento está vazio toda vez, e se não, novo Action<T>(), como mostrado abaixo:



Vamos dar uma olhada em como ela se compara à palavra-chave foreach em termos de desempenho. A imagem a seguir mostra os resultados do benchmark:



Pelos resultados do teste, é 40% mais lento do que usar diretamente a palavra-chave foreach, parece que, se não for necessário, é uma escolha melhor usar foreach diretamente, então existe alguma forma mais rápida?

para percorrimento de laços

Voltando ao nosso método mais antigo, que é usar a palavra-chave for para percorrer a coleção. Deve ser o método de travessia com melhor desempenho no momento, porque não requer código redundante como os anteriores (embora o indexador também seja verificado para evitar transbordamentos), e obviamente não verifica o número da versão, então em um ambiente multithreaded a coleção é alterada, e não haverá exceção ao usar for. O código do teste é o seguinte:

Vamos ver como vai ficar.



Parece ser assim que esperamos.Usar o loop for diretamente é 60% mais rápido do que foreach, um conjunto que antes levava 1 segundo para percorrer, agora leva apenas 400 milissegundos. Então, existe uma maneira mais rápida?

Use CollectionsMarshal

Após o .NET5, a comunidade dotnet implementou a classe CollectionsMarshal para melhorar o desempenho das operações de coleta. Esta classe implementa como acessar arrays nativos de tipos de coleção (se você viu meu [. .NET Performance Optimization - Você Deve Definir o Tamanho Inicial para Tipos de Coleção], você sabe que a implementação subjacente de muitas estruturas de dados são os arrays). Assim, ele pode pular todo tipo de detecção e acessar diretamente o array original, que deve ser o mais rápido. O código é o seguinte:

Você pode ver que o código gerado pelo compilador é muito eficiente.



O acesso direto ao array subjacente é muito perigoso, você precisa saber o que está fazendo com cada linha de código e ter testes suficientes. Os resultados do benchmark são os seguintes:



UauUsar o CollectionsMarshal é 79% mais rápido do que usar foreach, mas essa deveria ser a razão da otimização do JIT, não há grande diferença entre usar foreach e o loop de palavras-chave for Span.

resumo

Hoje falei com você sobre como percorrer rapidamente a coleção de Listas e, na maioria dos casos, é recomendado usar a palavra-chave foreach, que possui tanto verificação de overflow quanto controle multithread de número de versão, o que pode facilitar a escrita do código correto.

Se você precisa de alto desempenho e volumes de dados grandes, recomenda-se usar o for e o CollectionsMarshal.AsSpan diretamente para percorrer a coleção.

Link do código-fonte deste artigo:

O login do hiperlink está visível.

Link original:O login do hiperlink está visível.





Anterior:Explicação detalhada da arquitetura de mensagens AMQP do RabbitMQ
Próximo:Padrão padrão da cabeça de cristal de cabo de rede T568A e T568B
Postado em 2022-9-4 22:15:52 |
Aprenda a aprender
Postado em 2022-9-8 10:33:05 |
Aprenda a aprender
Postado em 2023-6-27 22:39:13 |
Olá 12306 Você pode me enviar uma mensagem privada com os dados
Disclaimer:
Todo software, material de programação ou artigos publicados pela Code Farmer Network são apenas para fins de aprendizado e pesquisa; O conteúdo acima não deve ser usado para fins comerciais ou ilegais, caso contrário, os usuários terão todas as consequências. As informações deste site vêm da Internet, e disputas de direitos autorais não têm nada a ver com este site. Você deve deletar completamente o conteúdo acima do seu computador em até 24 horas após o download. Se você gosta do programa, por favor, apoie um software genuíno, compre o registro e obtenha serviços genuínos melhores. Se houver qualquer infração, por favor, entre em contato conosco por e-mail.

Mail To:help@itsvse.com