Concorrência e Multithreading em C#: Guia Completo para Desenvolvedores .NET

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Concorrência e Multithreading em C#: de Thread a async/await



Aplicações modernas cada vez mais exigem a execução simultânea de várias tarefas: desde o processamento de requisições de servidores web até cálculos paralelos em programas desktop. Em C# (.NET), existe um poderoso arsenal de ferramentas para isso — desde threads clássicas (Thread) até construções de alto nível como async/await e a biblioteca Task Parallel Library (TPL). Neste artigo, vamos abordar os conceitos-chave de concorrência e multithreading, sua aplicação prática e melhores práticas.



O que são concorrência e multithreading?



Antes de ir para o código, é importante entender a diferença entre esses conceitos:



  • Concorrência (Concurrency) — a capacidade do programa de executar várias tarefas, alternando entre elas, criando a ilusão de execução simultânea. Isso pode ser implementado até mesmo em um único núcleo de processador.
  • Multithreading — uma forma de concorrência onde várias threads (threads) são executadas fisicamente ao mesmo tempo em um processador multi-core.
  • Paralelismo (Parallelism) — um subconjunto do multithreading, onde diferentes partes de uma tarefa são executadas estritamente ao mesmo tempo em núcleos diferentes.


Em C#, você pode usar tanto threads de baixo nível quanto abstrações que gerenciam threads automaticamente. A escolha depende da tarefa: para operações I/O-bound (trabalho com arquivos, rede), async/await é mais adequado, e para CPU-bound (cálculos), Parallel.For ou Task.



Criação e gerenciamento de threads: classe Thread



A classe System.Threading.Thread é a maneira mais baixo nível de trabalhar com threads em C#. Ela oferece controle total, mas requer sincronização cuidadosa.



using System;using System.Threading;

class Program{ static void Main() { Thread thread = new Thread(DoWork); thread.Start();

// A thread principal continua o trabalho for (int i = 0; i < 5; i++) { Console.WriteLine($"Thread principal: {i}"); Thread.Sleep(100); }

thread.Join(); // Aguarda a conclusão da thread filha Console.WriteLine("Trabalho concluído."); }

static void DoWork() { for (int i = 0; i < 5; i++) { Console.WriteLine($"Thread filha: {i}"); Thread.Sleep(150); } }}


Problemas do gerenciamento manual de threads:

  • Complexidade de sincronização (condições de corrida, deadlocks).
  • Alta sobrecarga na criação e destruição de threads.
  • Falta de suporte embutido para retorno de resultado.


Por isso, no C# moderno, prefere-se usar a Task Parallel Library.



Task Parallel Library (TPL) e async/await



A classe Task do namespace System.Threading.Tasks representa uma operação assíncrona. Em combinação com as palavras-chave async e await, ela permite escrever código assíncrono que se parece com código síncrono.



Exemplo básico com Task



using System;using System.Threading.Tasks;

class Program{ static async Task Main() { Console.WriteLine("Início do trabalho.");

// Inicia uma tarefa assíncrona Task<int> task = CalculateAsync(10);

// Enquanto a tarefa é executada, podemos fazer outra coisa Console.WriteLine("Fazendo outro trabalho...");

// Aguarda o resultado int result = await task; Console.WriteLine($"Resultado: {result}"); }

static async Task<int> CalculateAsync(int number) { await Task.Delay(1000); // Simula uma operação longa return number * number; }}

Blogs

Book Recommendations