Com a chegada do .NET 9, uma série de novas funcionalidades está prestes a revolucionar a forma como desenvolvemos aplicações assíncronas (Await async tasks). Dentre essas novidades, destaca-se o WhenEach, um recurso poderoso que facilita a manipulação de Tasks ao nosso favor. Neste artigo, exploraremos como essa funcionalidade pode ser utilizada para otimizar processos que envolvem múltiplas tarefas assíncronas e ações intermediárias.
O que é o WhenEach e por que ele é Importante?
O WhenEach é uma nova funcionalidade introduzida no .NET 9 que permite iterar sobre um conjunto de Tasks à medida que elas são concluídas, sem a necessidade de esperar que todas terminem. Isso é particularmente útil quando você tem várias tarefas para executar e deseja realizar ações específicas entre a execução dessas Tasks.
Cenário Hipotético: Upload em massa de usuários com envio condicional de E-mails
Para ilustrar o uso do WhenEach, consideremos um cenário hipotético:
- Desafio: Realizar um upload em massa de usuários para um sistema.
- Requisito Adicional: Enviar um e-mail para determinados usuários após o cadastro.
Fluxo Tradicional:
- O controlador recebe todos os usuários que precisam ser inseridos.
- Executa múltiplas chamadas assíncronas para uma API responsável pelo cadastro.
- Quando necessário, chama outra API para enviar um email ao usuário cadastrado.
Abaixo fiz um diagrama para ilustrar melhor como funcionária.
Como vocês podem ver o controlador vai chamar várias vezes essa mesma API e quando for necessário notificar, ele irá fazer a notificação via email.
Agora vamos ao código:
O código acima realiza operações assíncronas para simular tarefas que são concluídas em tempos aleatórios. Vamos detalhar cada parte do código:
Criação da lista de tarefas:
List>> tasks = Enumerable.Range(1, 5).Select(RandomExecution).ToList();
Enumerable.Range(1, 5)
: Gera uma sequência de números inteiros de 1 a 5.
.Select(RandomExecution)
: Aplica a função RandomExecution
a cada número da sequência, criando uma coleção de tarefas assíncronas (Task<KeyValuePair<int, bool>>
).
.ToList()
: Converte a coleção em uma lista para poder manipulá-la posteriormente.
Processamento das tarefas conforme elas são concluídas:
await foreach (var task in Task.WhenEach(tasks)) { KeyValuePairresult = await task; Console.WriteLine($"Task completed: {result.Key}"); if(result.Value){ Console.WriteLine($"Task {result.Key} sent an email!!!"); } }
Task.WhenEach(tasks)
: Este método retorna um IAsyncEnumerable<Task<KeyValuePair<int, bool>>>
, permitindo iterar sobre as tarefas à medida que elas são concluídas, independentemente da ordem.
await foreach
: Itera assincronamente sobre cada tarefa conforme ela é completada
await task
: Aguarda a conclusão da tarefa específica para obter o resultado
.Console.WriteLine($"Task completed: {result.Key}");
: Imprime no console que a tarefa com o número correspondente foi concluída
.Verificação condicional:
- Se
result.Value
fortrue
(ou seja, se o número da tarefa for par), imprime uma mensagem adicional indicando que um email foi enviado. ou no nosso exemplo hipotético, chamaríamos outra API para envio de email.
Definição da função RandomExecution
:
Parâmetro order
: Recebe um número inteiro que representa a ordem ou identificação da tarefa.
Random.Shared.Next(500, 5000)
: Gera um número aleatório entre 500 e 5000 milissegundos.
await Task.Delay(random);
: Aguarda de forma assíncrona pelo período de tempo aleatório gerado.
Retorno: Cria e retorna um KeyValuePair<int, bool>
onde:
- Chave (
order
): O número da tarefa. - Valor (
order % 2 == 0
): Um booleano que étrue
se o número da tarefa for par efalse
se for ímpar.
Resultado Final
Abaixo você pode conferir como seria a saída desse programa:
Vantagens do Uso do WhenEach
- Eficiência: Reduz o tempo total de processamento ao não esperar que todas as Tasks sejam concluídas.
- Responsividade: Ações podem ser executadas imediatamente após cada Task ser concluída.
- Escalabilidade: Melhora o desempenho em operações que envolvem um grande número de tarefas assíncronas.
Conclusão
O WhenEach introduzido no .NET 9 é uma ferramenta poderosa para desenvolvedores que buscam otimizar processos assíncronos (Await async tasks) em suas aplicações. Ao permitir a execução de ações intermediárias conforme as Tasks são concluídas, ele melhora significativamente a eficiência e a responsividade do sistema.
Referências
https://learn.microsoft.com/pt-br/dotnet/api/system.threading.tasks.task.wheneach?view=net-9.0