Dev (Back & Front)ARTIGO

Paralelismo e concorrência: exemplos práticos em .NET com C#

Veja nesse artigo o que seria paralelismo e concorrência através de exemplos práticos em .NET com C#Na computação, à medida que aumentaram as demandas…

Paralelismo e concorrência: exemplos práticos em .NET com C#
Imagem: Thiago Adriano

Veja nesse artigo o que seria paralelismo e concorrência através de exemplos práticos em .NET com C#

Na computação, à medida que aumentaram as demandas por eficiência e velocidade, surgiram diferentes abordagens para maximizar o uso dos recursos de hardware e lidar com múltiplas tarefas ao mesmo tempo.

Duas dessas abordagens são o Paralelismo e a Concorrência.

Neste post rápido demonstrarei de forma prática o que seria cada um deles.

Vamos la 🙂

Começando pelo Paralelismo, ele se refere à execução simultânea de múltiplas tarefas, geralmente em diferentes núcleos de um processador. Isso permite que tarefas sejam executadas ao mesmo tempo, aproveitando ao máximo o poder de processamento disponível.

Para ficar mais claro, imagine o seguinte cenário: você está trabalhando em um projeto que recebe uma lista de e-mails e deseja enviá-los para uma fila (um broker qualquer).

string[] emails = ["email1@fiap.com.br", "email2@fiap.com.br", "email3@fiap.com.br"];

foreach (var email in emails)
{
    SendEmailToQueue(email);
}

Console.WriteLine("Todos os e-mails foram enviados para a fila!");
Console.ReadLine();


static void SendEmailToQueue(string email)
{
    Console.WriteLine($"Enviando {email} para a fila... {Environment.CurrentManagedThreadId}");
    Thread.Sleep(500); 
    Console.WriteLine($"{email} foi enviado para a fila!");
}

Resultado:

Exemplo com for em C#

Note que este serviço foi executado em 1551ms e rodou somente na main thread 1.

Para que possamos paralelizar este fluxo e fazer com que os e-mails cheguem mais rapido na fila, nos podemos utilizar a classe classe Parallel do namespace System.Threading.Tasks.

Somente um ponto de atênção aqui pessoal, esse tipo de processo não é exclusivo do C#, você pode trabalhar com paralelismo com outras linguagens de programação também.

Bom, vamos atualizar o nosso exemplo anterior para que possamos ver como trabalhar com paralelismo:

using System.Diagnostics;

var stopWatch = new Stopwatch();
stopWatch.Start();
string[] emails = ["email1@fiap.com.br", "email2@fiap.com.br", "email3@fiap.com.br"];

Parallel.ForEach(emails, SendEmailToQueue);

stopWatch.Stop();

Console.WriteLine($"Todos os e-mails foram enviados para a fila! {stopWatch.ElapsedMilliseconds}ms ");
Console.ReadLine();


void SendEmailToQueue(string email)
{
    Console.WriteLine($"Enviando {email} para a fila... {Environment.CurrentManagedThreadId}");
    Thread.Sleep(500);
    Console.WriteLine($"{email} foi enviado para a fila!");
}

Neste exemplo nós atualizamos o foreach para o Parallel.foreach. (Bem conhecido pela comunidade de desenvolvedores .NET).

Resultado:

Programação paralela com .NET C#

Note que tivemos um ganho significativo no processamento do nosso sistema, o que havia sido processado em 1551ms caiu para 543ms.

Isso foi possivel porque nós utilizamos oParallel.ForEach, que divide o trabalho entre múltiplas threads, permitindo que as operações sejam executadas em paralelo.

Mas antes de avancarmos para o próximo tópico deste post, você sabe o que seria uma thread?

Caso a sua resposta seja não, uma thread é a menor unidade de processamento que um sistema operacional pode agendar.

Em termos simples, uma thread é uma sequência de instruções que pode ser executada independentemente.

Cada thread dentro de um processo compartilha o mesmo espaço de memória, o que permite que elas se comuniquem e compartilhem dados facilmente, mas também requer uma sincronização cuidadosa para evitar conflitos e inconsistências.

Agora avançando para o nosso próximo tópico sobre concorrência, ela se refere à capacidade de uma aplicação lidar com múltiplas tarefas, alternando entre elas para maximizar a eficiência.

Isso não significa que as tarefas estão sendo executadas ao mesmo tempo, mas sim que a aplicação gerencia várias tarefas de maneira que pareça simultânea.

Para que possamos entender como funciona concorrência na prática, imagine que você é um desenvolvedor trabalhando em um aplicativo de e-commerce. Você recebeu uma demanda para implementar uma funcionalidade que processa pedidos de clientes e, ao mesmo tempo, verifica se há atualizações de estoque para os produtos.

A seguir você tem um exemplo em C# que simula esse cenário usando concorrência:

using System.Diagnostics; var stopWatch = new Stopwatch(); stopWatch.Start(); Task processOrders = ProcessOrdersAsync(); Task checkInventoryUpdates = CheckInventoryUpdatesAsync(); await Task.WhenAll(processOrders, checkInventoryUpdates); stopWatch.Stop(); Console.WriteLine($"Processamento de pedidos e verificação de estoque concluídos. {stopWatch.ElapsedMilliseconds}ms"); async Task ProcessOrdersAsync() {     Console.WriteLine($"Iniciando processamento de pedidos... {Environment.CurrentManagedThreadId}");     await Task.Delay(5000);     Console.WriteLine($"Processamento de pedidos concluído. {Environment.CurrentManagedThreadId}"); } async Task CheckInventoryUpdatesAsync() {     Console.WriteLine($"Verificando atualizações de estoque... {Environment.CurrentManagedThreadId}");     await Task.Delay(3000);     Console.WriteLine($"Atualizações de estoque verificadas. {Environment.CurrentManagedThreadId}"); }

Neste exemplo, ProcessOrdersAsync simula o processamento de pedidos dos clientes, enquanto CheckInventoryUpdatesAsync simula a verificação de atualizações no estoque.

Ambas as tarefas são iniciadas quase simultaneamente, mas são executadas de forma concorrente, o que significa que o sistema operacional e o runtime do .NET gerenciam a alternância entre as tarefas para maximizar a eficiência.

Resultado:

Notem que o sistema iniciou na thread principal e depois finalizou em outra thread. Este comportamento é devido ao uso do pool de threads pelo runtime do .NET para executar operações assíncronas.

Bom, espero que tenham entendido como Paralelismo e Concorrencia funcionam e que tenham gostado deste post.

Até mais pessoal.

Thiago AdrianoAutor

Microsoft (MVP), atualmente trabalha como Arquiteto de Software para TV Bandeirantes. Nesses últimos anos, focou nas tecnologias criadas pela Microsoft, mas sempre esteve antenado para as novas tecnologias que estão surgindo no mercado. Em um breve resumo, é uma pessoa apaixonada pelo que faz, tem a sua profissão como hobby.

Ver perfil