Henceforth Tecnologia
Blog
Performance27 de jul. 2026

Concorrência e paralelismo: a diferença que muda sua conta de cloud

"Um núcleo de CPU só faz uma coisa de cada vez." Fechamos o post anterior com essa frase, e ela parece óbvia demais pra merecer um post inteiro. Mas é a raiz de praticamente toda decisão de otimização que vale a pena tomar. Antes de otimizar qualquer coisa, você precisa entender como a linguagem e o runtime da sua aplicação lidam com isso.

Single-thread vs. multi-thread, na prática

Uma thread é, essencialmente, uma sequência de instruções sendo executada. Um processo single-thread executa uma instrução de cada vez, do início ao fim. Um processo multi-thread pode ter várias dessas sequências rodando "ao mesmo tempo", dividindo o trabalho.

Na prática, o que importa saber é: quando uma requisição pesada (CPU-bound) chega, ela trava o atendimento das outras requisições, ou não? Numa aplicação single-thread, se essa única thread está ocupada calculando algo pesado, nenhuma outra requisição é atendida enquanto isso não terminar. Numa aplicação multi-thread bem configurada, outras threads continuam livres para atender o restante do tráfego.

Isso não é só teoria de sistema operacional: é a diferença entre uma aplicação que degrada aos poucos sob carga e uma que trava inteira porque uma única requisição pesada bloqueou tudo.

Concorrência não é paralelismo

Os dois termos são usados como sinônimos com frequência, mas descrevem coisas diferentes:

  • Concorrência é a capacidade de lidar com várias tarefas ao mesmo tempo, alternando entre elas. Não exige mais de um núcleo de CPU, exige apenas que o sistema saiba intercalar o trabalho.
  • Paralelismo é executar várias tarefas literalmente ao mesmo tempo, em núcleos de CPU diferentes.

Um único núcleo pode ser concorrente sem nunca ser paralelo: ele alterna entre tarefas rápido o suficiente para parecer que está fazendo tudo ao mesmo tempo, mas, a cada instante, só uma instrução está de fato sendo executada. Paralelismo real exige múltiplos núcleos trabalhando ao mesmo tempo.

Como cada linguagem lida com isso

Cada linguagem e runtime resolve esse problema de um jeito diferente, e isso muda completamente como você deve pensar em otimização:

  • Node.js roda seu código JavaScript num único núcleo (event loop single-thread). É ótimo em concorrência para I/O — múltiplas requisições esperando banco de dados, por exemplo, não bloqueiam umas às outras — mas uma tarefa pesada de CPU trava o event loop inteiro, e nenhuma outra requisição é atendida enquanto ela não termina.
  • Python tem múltiplas threads reais, mas o GIL (Global Interpreter Lock) impede que duas threads executem bytecode Python ao mesmo tempo, mesmo com vários núcleos disponíveis. Trabalho de I/O se beneficia de threads; trabalho pesado de CPU não, a menos que você use múltiplos processos em vez de múltiplas threads.
  • Go foi desenhado pra isso: goroutines são threads leves, gerenciadas pelo próprio runtime, distribuídas automaticamente entre os núcleos disponíveis. É paralelismo de verdade, sem que você precise gerenciar threads do sistema operacional na mão.
  • Java usa threads nativas do sistema operacional, com paralelismo real entre núcleos. O custo vem de outro lugar: cada thread tem overhead de memória, e coordenar acesso a dados compartilhados entre muitas threads exige cuidado.

Não é sobre qual linguagem é "melhor", é sobre entender qual modelo a sua aplicação usa, pra tomar decisões de dimensionamento coerentes com ele.

Por que isso é, no fundo, uma questão de custo

Esse entendimento se conecta direto com o que já discutimos sobre performance e custo: dimensionar CPU errado pra sua realidade de concorrência é jogar dinheiro fora. Pagar por oito núcleos pra rodar um único processo Node.js sem usar cluster, ou uma aplicação Python que faz tudo com threads num fluxo CPU-bound, é pagar por paralelismo que a aplicação nunca vai conseguir usar.

Como a Henceforth ajuda

Analisamos como cada aplicação usa concorrência e paralelismo na prática, e comparamos isso com o hardware contratado. Na maioria dos casos, encontramos núcleos pagos e nunca aproveitados, ou o oposto: aplicações single-thread sufocadas numa única CPU pequena, quando o problema real era arquitetural.

Se você não sabe dizer com segurança se a sua aplicação está limitada por concorrência mal aproveitada, fale com a nossa equipe e vamos descobrir juntos.