Resumo
No campo do processamento de dados, as oportunidades de otimização muitas vezes ficam inexploradas. Este post do blog explora a transformação de uma solução serial de ETL e notificações, que dependia de multithreading e ponteiros, para um sistema paralelizado e altamente otimizado usando a biblioteca .NET DataFlow.
Apresentamos um estudo de caso onde o desempenho de uma aplicação que processa grandes volumes de dados é significativamente melhorado ao utilizar a biblioteca DataFlow Parallel.
Introdução
O processamento de dados é uma solução recorrente na indústria e, às vezes, uma oportunidade perdida de melhorar a otimização em alguns projetos. Utilizando soluções da biblioteca .NET DataFlow Parallel, que envolvem otimização de código com paralelismo, podemos lidar facilmente com tarefas de processamento de dados desde o início de uma maneira que faz sentido.
Apresentaremos um cenário em que melhoramos o desempenho da aplicação e agilizamos o processamento de grandes volumes de dados, cerca de 80 milhões de registros, por meio da utilização do .NET DataFlow para paralelização de código.
Solução Serial
A solução inicial envolve um processo de carregamento (Load) de thread única, que lida sequencialmente com o agrupamento de dados, o envio de lotes para o armazenamento e a finalização dos dados restantes. Embora a paralelização pudesse melhorar esse processo, ela introduz desafios como transferência de dados, sincronização e bloqueio de objetos.
Neste caso específico, existe um processo de carga (Load) que recebe dados após o processo de transformação. As responsabilidades dessa classe Load incluem:
- Agrupar dados em lotes
- Enviar lotes para o armazenamento
- Compilar os dados restantes em um lote final
Introdução ao DataFlow
A biblioteca .NET DataFlow é um conjunto de ferramentas prático para lidar com tarefas paralelas sem complicar as coisas, gerenciando as complexidades da paralelização para que você possa se concentrar em outras tarefas de desenvolvimento.
Imagine-a como um modelo de pipeline que facilita o trabalho pesado, permitindo que você se concentre na lógica essencial. O mais interessante? Além de cuidar da paralelização, ela também garante uma comunicação suave entre os diferentes blocos. Você decide como os dados se movem e são armazenados.
Além disso, ela é proficiente em gerenciar threads e otimizar as capacidades do computador para melhorar a eficiência. Seja você alguém que prefira um pipeline simples ou queira experimentar com gráficos em rede, o DataFlow é um companheiro confiável que simplifica o processo.
Aspectos-chave do modelo DataFlow
- Comunicação síncrona/assíncrona com passagem de mensagens no processo
- Controle explícito sobre o armazenamento e o fluxo de dados entre os blocos
- Armazenamento de dados e agendamento de trabalho quando disponíveis
- Gerenciamento de threads para aumentar a taxa de transferência
Quando usar o modelo DataFlow:
- Fluxos de dados de granulação mais ampla, onde um trabalho substancial ou bem definido é necessário.
- Para cenários de processamento de dados, tanto em pipelines lineares quanto em gráficos em rede.
Como funciona
O comportamento principal dos blocos DataFlow é armazenar e processar dados de maneiras diferentes.
- Blocos de origem são os pontos de origem dos dados. Você lê deles.
- Blocos de destino são os receptores de dados. Você escreve neles.
- Blocos propagadores atuam como fontes e receptores ao mesmo tempo.
Para criar um pipeline DataFlow, você precisa seguir estas etapas:
- Criação de blocos: Gere os blocos necessários, utilizando os pré-definidos ou criando blocos personalizados.
- Linkagem do pipeline: Conecte os blocos no pipeline usando o método “LinkTo”, formando um fluxo estruturado para o processamento de dados.
- Tratamento de conclusão: Implemente mecanismos para tratar a conclusão do pipeline, garantindo que todo o processo seja finalizado de forma adequada.
- Postagem de dados: Introduza dados no pipeline, postando-os pelos canais apropriados, iniciando o fluxo de informações e o processamento subsequente.
Integração do DataFlow
O modelo DataFlow depende de tarefas bem definidas e desacopladas. O post do blog detalha a configuração de blocos, apresentando um bloco personalizado (Discriminador), composto por ActionBlock, BroadcastBlock e BatchBlocks para agrupamento eficiente de dados.
Antes de trabalhar com o DataFlow, é crucial reconhecer que o modelo subjacente depende de tarefas bem definidas e desacopladas. Isso implica que as tarefas dentro do sistema são cuidadosamente definidas e operam independentemente, promovendo modularidade e flexibilidade no processamento paralelizado. Compreender esse aspecto fundamental é essencial para aproveitar todo o potencial do DataFlow, pois ele permite uma coordenação e execução eficazes de diversas tarefas dentro do fluxo de trabalho paralelizado.
Configuração
Os blocos podem ser configurados para se adaptar aos requisitos específicos. Neste caso, o processo envolve especificar vários parâmetros. Especificamente, fornecemos informações sobre a capacidade, token de cancelamento e grau máximo de paralelismo para os Blocos de Transformação e Ação. Além disso, para os blocos Batch, a configuração envolve definir o número máximo de grupos, garantindo que cada bloco opere em conformidade com os parâmetros desejados, melhorando a adaptabilidade e a eficiência do sistema DataFlow como um todo.
Definir blocos
A solução com a biblioteca DataFlow inclui um CustomBlock (Discriminador) que recebe dados da fase de Transformação e agrupa cada pedaço de dado recebido para continuar o processamento.
O bloco personalizado é composto por um ActionBlock que funciona como um roteador para armazenar dados corretamente, um BroadcastBlock para compartilhar cópias dos lotes e um dicionário de BatchBlocks para organizar os dados.
Resultados
Com o auxílio dos recursos do .NET DataFlow, conseguimos dividir as tarefas no processo e executá-las simultaneamente. Essa abordagem de paralelização nos permitiu usar todo o potencial dos recursos de hardware disponíveis, levando a uma diminuição significativa no tempo de execução total. Os benefícios da paralelização são notáveis em situações onde a carga de trabalho é inherentemente paralelizável. Tarefas que antes eram realizadas sequencialmente podem agora ser processadas simultaneamente, resultando em um aumento considerável na taxa de transferência. Essa melhoria não só aprimora a experiência do usuário ao fornecer resultados mais rápidos, como também permite lidar com conjuntos de dados maiores ou mais solicitações simultâneas. Além disso, a simplicidade de expressar paralelismo através do .NET DataFlow tornou o código mais fácil de manter e legível. As abstrações de alto nível da framework simplificaram a implementação do processamento paralelo, permitindo que a equipe de desenvolvimento se concentrasse na lógica das tarefas individuais em vez de nos detalhes complicados de gerenciar a concorrência.