<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Jair Rodrigues Blog]]></title><description><![CDATA[Jair Rodrigues Blog]]></description><link>https://jairblog.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Wed, 02 Sep 2026 01:18:39 GMT</lastBuildDate><atom:link href="https://jairblog.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Usando o n8n como backend: automações que eliminam APIs simples]]></title><description><![CDATA[Muitos desenvolvedores olham para o n8n e veem apenas uma alternativa open-source ao Zapier. Uma ferramenta para colar planilhas no Slack ou disparar e-mails de marketing.
Embora ele faça isso muito bem, essa visão é limitada.
Quando olhamos para o n...]]></description><link>https://jairblog.hashnode.dev/usando-o-n8n-como-backend-automacoes-que-eliminam-apis-simples</link><guid isPermaLink="true">https://jairblog.hashnode.dev/usando-o-n8n-como-backend-automacoes-que-eliminam-apis-simples</guid><category><![CDATA[n8n]]></category><category><![CDATA[n8n workflows]]></category><category><![CDATA[APIs]]></category><category><![CDATA[backend]]></category><category><![CDATA[mvp]]></category><category><![CDATA[webhooks]]></category><dc:creator><![CDATA[Jair Rodrigues]]></dc:creator><pubDate>Thu, 15 Jan 2026 12:22:06 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1768502681410/682a0b80-1515-49de-aeaf-83df0a626d3b.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Muitos desenvolvedores olham para o <strong>n8n</strong> e veem apenas uma alternativa open-source ao Zapier. Uma ferramenta para colar planilhas no Slack ou disparar e-mails de marketing.</p>
<p>Embora ele faça isso muito bem, essa visão é limitada.</p>
<p>Quando olhamos para o n8n com a mentalidade de engenharia de software, ele se transforma em um poderoso <strong>orquestrador de backend</strong>. Para MVPs, micro-serviços auxiliares e funcionalidades específicas, você pode literalmente substituir uma API Node.js ou Python inteira por um único workflow bem estruturado.</p>
<p>Neste artigo, vamos explorar como transformar o n8n em um "backend invisível", focando na arquitetura Webhook-Processamento-Resposta.</p>
<h2 id="heading-o-conceito-n8n-como-camada-de-servico">O conceito: n8n como Camada de Serviço</h2>
<p>No desenvolvimento tradicional, se você precisa de um endpoint para receber um formulário, validar dados, salvar no banco e notificar o time, você subiria um servidor (Express, FastApi, NestJS), configuraria rotas, controllers, serviços e DTOs.</p>
<p>No n8n, a lógica é a mesma, mas a abstração é visual. A arquitetura muda para:</p>
<ol>
<li><p><strong>Input:</strong> Webhook (o endpoint da sua API).</p>
</li>
<li><p><strong>Controller/Logic:</strong> Nodes de IF, Switch e Code.</p>
</li>
<li><p><strong>Service/Model:</strong> Nodes de Banco de Dados (Postgres, Supabase) ou APIs externas.</p>
</li>
<li><p><strong>Output:</strong> Respond to Webhook (o JSON de retorno).</p>
</li>
</ol>
<p>Isso não é apenas "arrastar bloquinhos"; é <strong>orquestração de eventos</strong>.</p>
<h2 id="heading-a-arquitetura-do-workflow">A Arquitetura do Workflow</h2>
<p>Para que o n8n funcione como backend, o segredo está em fechar o ciclo de requisição. Diferente de uma automação assíncrona (fire-and-forget), aqui o cliente (seu frontend ou app) fica esperando uma resposta.</p>
<p>A estrutura básica é:</p>
<p><code>Webhook Node</code> → <code>Processamento</code> → <code>Respond to Webhook Node</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1768477102653/7130e5ca-5b1a-4538-9f23-2e269d1db0c0.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-1-o-endpoint-webhook-node">1. O Endpoint (Webhook Node)</h3>
<p>Ao arrastar um nó de Webhook, você define o método (GET, POST, etc.) e o caminho. O n8n gera uma URL de produção. Pronto, você tem um endpoint exposto.</p>
<h3 id="heading-2-a-logica-switch-if-e-http-request">2. A Lógica (Switch, IF e HTTP Request)</h3>
<p>Aqui acontece a mágica. Em vez de escrever <code>if (data.status === 'active')</code>, você usa um nó <strong>Switch</strong> ou <strong>IF</strong>. Se precisa consultar uma API externa (como um gateway de pagamento ou API de IA), usa o <strong>HTTP Request</strong>.</p>
<h3 id="heading-3-o-retorno-respond-to-webhook">3. O Retorno (Respond to Webhook)</h3>
<p>Este é o nó que diferencia um backend de uma automação comum. Você define o status HTTP (200, 400, 500) e o corpo do JSON que o seu frontend receberá.</p>
<h2 id="heading-exemplo-real-validacao-de-lead-e-enriquecimento">Exemplo Real: Validação de Lead e Enriquecimento</h2>
<p>Imagine que você tem uma Landing Page. Ao receber um cadastro, você quer:</p>
<ol>
<li><p>Validar se o e-mail é corporativo.</p>
</li>
<li><p>Se for Gmail/Hotmail, rejeitar imediatamente.</p>
</li>
<li><p>Se for corporativo, salvar no banco e retornar "Sucesso".</p>
</li>
</ol>
<p><strong>Como fazer isso no código:</strong> Escrever regex, configurar conexão com banco, tratamento de erro <code>try/catch</code>.</p>
<p><strong>Como fazer no n8n (em minutos):</strong></p>
<ol>
<li><p><strong>Webhook (POST):</strong> Recebe <code>{ "email": "</code><a target="_blank" href="mailto:joao@empresa.com"><code>joao@empresa.com</code></a><code>" }</code>.</p>
</li>
<li><p><strong>Code Node / IF:</strong> Verifica se o domínio contém "gmail" ou "hotmail".</p>
</li>
<li><p><strong>Branch True (Erro):</strong> Conecta direto ao <strong>Respond to Webhook</strong> com Status 400 e JSON <code>{"error": "Apenas e-mails corporativos"}</code>.</p>
</li>
<li><p><strong>Branch False (Sucesso):</strong></p>
<ul>
<li><p>Insere no Supabase/Postgres.</p>
</li>
<li><p>Manda notificação no Slack/Discord.</p>
</li>
<li><p>Conecta ao <strong>Respond to Webhook</strong> com Status 201 e JSON <code>{"message": "Cadastro realizado"}</code>.</p>
</li>
</ul>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1768478552485/3b1829b3-81b8-4973-abd5-68f37ab05eab.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-o-pulo-do-gato-code-node">O "Pulo do Gato": Code Node</h2>
<p>É aqui que a visão de engenharia brilha. Você não está limitado aos nós prontos. O <strong>Code Node</strong> permite rodar JavaScript (ou Python) puro dentro do fluxo.</p>
<p>Isso é essencial para:</p>
<ul>
<li><p>Tratamento complexo de arrays.</p>
</li>
<li><p>Criptografia/Hash de dados antes de salvar.</p>
</li>
<li><p>Parsing de regex avançado.</p>
</li>
</ul>
<p>JavaScript</p>
<pre><code class="lang-python">// Exemplo de manipulação dentro do n8n
const email = items[<span class="hljs-number">0</span>].json.body.email;
const domain = email.split(<span class="hljs-string">'@'</span>)[<span class="hljs-number">1</span>];

<span class="hljs-keyword">if</span> (domain === <span class="hljs-string">'gmail.com'</span>) {
  <span class="hljs-keyword">return</span> { json: { valid: false, reason: <span class="hljs-string">"Free provider"</span> } };
}

<span class="hljs-keyword">return</span> { json: { valid: true, domain: domain } };
</code></pre>
<p>O n8n deixa de ser uma ferramenta "No-code" e vira "Low-code". Você codifica apenas a lógica de negócio complexa, deixando a infraestrutura (receber requisição, conectar com serviços) para a ferramenta.</p>
<h2 id="heading-quando-o-n8n-substitui-um-backend">Quando o n8n substitui um Backend?</h2>
<p>Essa abordagem é perfeita para:</p>
<ul>
<li><p><strong>MVPs:</strong> Valide sua ideia sem configurar servidores AWS/DigitalOcean.</p>
</li>
<li><p><strong>Proxy de APIs:</strong> Precisa esconder sua chave de API da OpenAI do frontend? Crie um endpoint no n8n que recebe a pergunta, chama a OpenAI (com a chave segura no servidor n8n) e devolve a resposta.</p>
</li>
<li><p><strong>Webhooks de Terceiros:</strong> Receber eventos do Stripe ou GitHub e processá-los.</p>
</li>
<li><p><strong>CRUDs Simples:</strong> Leitura e escrita básica em bancos de dados.</p>
</li>
</ul>
<h2 id="heading-quando-nao-usar-limites-reais">Quando NÃO usar (Limites Reais)</h2>
<p>Como engenheiros, precisamos saber as limitações das ferramentas:</p>
<ol>
<li><p><strong>Baixa Latência Extrema:</strong> O n8n tem um overhead. Se você precisa de respostas em sub-milissegundos, use Go ou Rust.</p>
</li>
<li><p><strong>Lógica Stateful Complexa:</strong> Se sua aplicação depende de Websockets ou sessões de usuário complexas na memória, o n8n não é a ferramenta certa.</p>
</li>
<li><p><strong>Processamento Pesado:</strong> Não tente processar vídeos ou grandes datasets diretamente no fluxo (a menos que o n8n apenas orquestre o envio para um serviço dedicado).</p>
</li>
</ol>
<h2 id="heading-conclusao">Conclusão</h2>
<p>O n8n é mais do que automação de tarefas; é uma camada de backend visual ágil. Para engenheiros e desenvolvedores, ele oferece a velocidade do <em>no-code</em> com a flexibilidade do código real quando necessário.</p>
<p>No próximo projeto ou feature pequena, antes de dar <code>npm init</code> e criar toda uma estrutura de servidor, pergunte-se: <strong>"Eu poderia resolver isso com um webhook e três nós?"</strong></p>
<p>Muitas vezes, a resposta é sim.</p>
]]></content:encoded></item><item><title><![CDATA[Brain-CLI: Como criei meu próprio Assistente de Terminal com Python e IA]]></title><description><![CDATA[Dizem que a preguiça é a principal virtude de um programador. Se você precisa fazer a mesma coisa duas vezes, automatize. Se precisa fazer três vezes, crie uma ferramenta para isso.
Como desenvolvedor, eu me pegava constantemente saindo do terminal p...]]></description><link>https://jairblog.hashnode.dev/brain-cli-como-criei-meu-proprio-assistente-de-terminal-com-python-e-ia</link><guid isPermaLink="true">https://jairblog.hashnode.dev/brain-cli-como-criei-meu-proprio-assistente-de-terminal-com-python-e-ia</guid><category><![CDATA[cli]]></category><category><![CDATA[AI]]></category><category><![CDATA[Python]]></category><category><![CDATA[terminal]]></category><category><![CDATA[terminal command]]></category><category><![CDATA[Script]]></category><dc:creator><![CDATA[Jair Rodrigues]]></dc:creator><pubDate>Tue, 06 Jan 2026 03:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1768502642726/967b9292-56ad-46ca-bac5-bdff2acc7181.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Dizem que a preguiça é a principal virtude de um programador. Se você precisa fazer a mesma coisa duas vezes, automatize. Se precisa fazer três vezes, crie uma ferramenta para isso.</p>
<p>Como desenvolvedor, eu me pegava constantemente saindo do terminal para pesquisar no Google coisas como: <em>"Como descompactar um arquivo .tar.gz?"</em> <em>"Qual o comando git para desfazer o último commit sem perder as alterações?"</em> <em>"Como listar processos rodando na porta 8080?"</em></p>
<p>Essa troca de contexto mata a produtividade. A solução? Criar um "segundo cérebro" que vive onde eu trabalho: no terminal.</p>
<p>Apresento o <strong>Brain CLI</strong>, uma ferramenta open-source que desenvolvi para transformar linguagem natural em comandos de terminal, usando IA e memória local.</p>
<h2 id="heading-o-conceito-ia-memoria-local">O Conceito: IA + Memória Local</h2>
<p>A ideia não era apenas criar um wrapper para o ChatGPT. Eu precisava de algo rápido, que funcionasse offline para comandos recorrentes e que fosse extremamente leve.</p>
<p>O <strong>Brain CLI</strong> opera de forma híbrida:</p>
<ol>
<li><p><strong>Inteligência Artificial (Groq/Llama 3):</strong> Para interpretar pedidos complexos em linguagem natural.</p>
</li>
<li><p><strong>SQLite Local:</strong> Para armazenar "snippets" e comandos que eu uso sempre, eliminando a latência da rede.</p>
</li>
</ol>
<h2 id="heading-sob-o-capo-a-engenharia">Sob o Capô: A Engenharia</h2>
<p>Construir uma CLI moderna em Python vai muito além de <code>print()</code> e <code>input()</code>. Para garantir uma experiência de usuário (DX) fluida, utilizei uma stack focada em performance e estética:</p>
<ul>
<li><p><strong>Typer:</strong> Para criar a interface de linha de comando. É intuitivo e gera <em>help pages</em> automáticas baseadas nos <em>type hints</em> do Python.</p>
</li>
<li><p><strong>Rich:</strong> O terminal não precisa ser preto e branco. Usei o Rich para renderizar tabelas, painéis, <em>syntax highlighting</em> e loadings animados.</p>
</li>
<li><p><strong>Groq SDK:</strong> A chave para a velocidade. Utilizo a API da Groq rodando modelos Llama 3 para obter respostas quase instantâneas.</p>
</li>
</ul>
<h3 id="heading-o-resultado-visual">O Resultado Visual</h3>
<p>Dê uma olhada em como ele funciona na prática:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1768442772742/710baba3-b09a-4bea-8b31-bd462753f8e7.gif" alt class="image--center mx-auto" /></p>
<h2 id="heading-de-script-local-a-pip-install">De Script Local a <code>pip install</code></h2>
<p>O maior "pulo do gato" deste projeto foi a distribuição. Um script Python na minha máquina é útil só para mim. Uma ferramenta no <strong>PyPI</strong> é útil para o mundo.</p>
<p>Configurei o empacotamento com <code>pyproject.toml</code> e publiquei o pacote. Agora, a instalação é agnóstica de sistema operacional. Seja no Linux, Windows ou macOS, basta rodar:</p>
<pre><code class="lang-bash">pip install brain-cli
</code></pre>
]]></content:encoded></item><item><title><![CDATA[Engenharia de Software: Quando usar Threads e quando usar Processos em Python?]]></title><description><![CDATA[Muitos iniciantes em Python se deparam com um problema comum: ao tentar processar uma grande quantidade de dados, o script demora horas. A primeira reação é tentar usar Threads, mas em Python, isso nem sempre funciona como esperado devido ao Global I...]]></description><link>https://jairblog.hashnode.dev/engenharia-de-software-quando-usar-threads-e-quando-usar-processos-em-python</link><guid isPermaLink="true">https://jairblog.hashnode.dev/engenharia-de-software-quando-usar-threads-e-quando-usar-processos-em-python</guid><category><![CDATA[GIL]]></category><category><![CDATA[multithreading]]></category><category><![CDATA[CPU Bound ]]></category><category><![CDATA[Threading]]></category><category><![CDATA[Python]]></category><dc:creator><![CDATA[Jair Rodrigues]]></dc:creator><pubDate>Mon, 15 Dec 2025 03:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1768502718653/9a595223-314d-424a-96ea-a4066fcac317.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Muitos iniciantes em Python se deparam com um problema comum: ao tentar processar uma grande quantidade de dados, o script demora horas. A primeira reação é tentar usar <em>Threads</em>, mas em Python, isso nem sempre funciona como esperado devido ao <strong>Global Interpreter Lock (GIL)</strong>. Neste artigo, vou mostrar, com código e dados reais, a diferença de performance entre execução Sequencial, Multithreading e Multiprocessing em uma tarefa de alta carga de CPU.</p>
<hr />
<h2 id="heading-o-cenario-de-teste-cpu-bound">O Cenário de Teste: CPU-Bound</h2>
<p>Para que nosso teste seja justo e cientificamente relevante, precisamos simular uma tarefa <strong>CPU-Bound</strong> (limitada pela CPU). Isso significa uma tarefa que exige processamento matemático pesado, e não espera por rede ou disco (I/O).</p>
<p>Vamos criar uma função que realiza cálculos matemáticos intensivos repetidas vezes.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> time
<span class="hljs-keyword">import</span> math
<span class="hljs-keyword">import</span> concurrent.futures
<span class="hljs-keyword">import</span> multiprocessing

<span class="hljs-comment"># Função que simula alta carga de CPU</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">heavy_computation</span>(<span class="hljs-params">x</span>):</span>
    result = <span class="hljs-number">0</span>
    <span class="hljs-comment"># Loop longo com cálculos matemáticos</span>
    <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">1</span>, <span class="hljs-number">1000000</span>):
        result += math.sqrt(i * x)
    <span class="hljs-keyword">return</span> result

<span class="hljs-comment"># Vamos processar 20 tarefas pesadas</span>
data_list = list(range(<span class="hljs-number">1</span>, <span class="hljs-number">21</span>))
</code></pre>
<hr />
<h2 id="heading-1-a-abordagem-sequencial-o-baseline">1. A Abordagem Sequencial (O Baseline)</h2>
<p>A execução sequencial é o padrão do Python. O interpretador executa uma linha, espera terminar e vai para a próxima. É previsível e fácil de debugar, mas utiliza apenas <strong>um núcleo</strong> do seu processador, deixando todo o resto da sua máquina ociosa.</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">run_sequential</span>():</span>
    start_time = time.time()
    results = [heavy_computation(x) <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> data_list]
    end_time = time.time()
    print(<span class="hljs-string">f"Sequencial: <span class="hljs-subst">{end_time - start_time:<span class="hljs-number">.2</span>f}</span> segundos"</span>)
</code></pre>
<hr />
<h2 id="heading-2-a-armadilha-do-multithreading-e-o-gil">2. A "Armadilha" do Multithreading e o GIL</h2>
<p>Aqui é onde a teoria da computação se encontra com a prática. Muitos desenvolvedores assumem que "Threads" significam "Paralelismo". Em linguagens como Java ou C++, isso é verdade. No Python (implementação CPython), não é bem assim.</p>
<p>O <strong>GIL (Global Interpreter Lock)</strong> é um mecanismo que impede que múltiplas threads nativas executem bytecodes Python simultaneamente. Isso existe para proteger o gerenciamento de memória do Python, que não é <em>thread-safe</em>.</p>
<p>Ou seja: mesmo criando 10 threads, o Python só permite que <strong>uma</strong> rode por vez. Em tarefas de CPU, o custo de alternar entre as threads (context switching) pode até tornar o código mais lento do que o sequencial.</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">run_threading</span>():</span>
    start_time = time.time()
    <span class="hljs-comment"># ThreadPoolExecutor é ótimo para I/O, mas vamos testar na CPU</span>
    <span class="hljs-keyword">with</span> concurrent.futures.ThreadPoolExecutor() <span class="hljs-keyword">as</span> executor:
        results = list(executor.map(heavy_computation, data_list))
    end_time = time.time()
    print(<span class="hljs-string">f"Threading: <span class="hljs-subst">{end_time - start_time:<span class="hljs-number">.2</span>f}</span> segundos"</span>)
</code></pre>
<hr />
<h2 id="heading-3-a-solucao-multiprocessing">3. A Solução: Multiprocessing</h2>
<p>Se threads compartilham o mesmo processo e memória (presos ao GIL), a solução para usar todo o poder do hardware é criar <strong>múltiplos processos</strong>.</p>
<p>O módulo <code>multiprocessing</code> (ou <code>ProcessPoolExecutor</code>) cria novas instâncias do interpretador Python. Cada processo tem seu próprio espaço de memória e seu próprio GIL. Dessa forma, se você tem um processador com 4, 8 ou 12 núcleos, o Python pode rodar cálculos em todos eles ao mesmo tempo.</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">run_multiprocessing</span>():</span>
    start_time = time.time()
    <span class="hljs-comment"># ProcessPoolExecutor cria processos independentes</span>
    <span class="hljs-keyword">with</span> concurrent.futures.ProcessPoolExecutor() <span class="hljs-keyword">as</span> executor:
        results = list(executor.map(heavy_computation, data_list))
    end_time = time.time()
    print(<span class="hljs-string">f"Multiprocessing: <span class="hljs-subst">{end_time - start_time:<span class="hljs-number">.2</span>f}</span> segundos"</span>)
</code></pre>
<blockquote>
<p><strong>Nota Técnica:</strong> O Multiprocessing consome mais memória RAM, pois duplica os recursos para cada processo. É um <em>trade-off</em> clássico de engenharia: trocamos memória por velocidade de processamento.</p>
</blockquote>
<hr />
<h2 id="heading-resultados-na-pratica">Resultados na Prática</h2>
<p>Para validar a teoria, executei o script completo na minha máquina. Abaixo está o código completo para você reproduzir o teste (se estiver no Windows, é obrigatório usar o <code>if __name__ == '__main__':</code> para o multiprocessing funcionar).</p>
<h3 id="heading-o-script-completo">O Script Completo</h3>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> time
<span class="hljs-keyword">import</span> math
<span class="hljs-keyword">import</span> concurrent.futures

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">heavy_computation</span>(<span class="hljs-params">x</span>):</span>
    result = <span class="hljs-number">0</span>
    <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">1</span>, <span class="hljs-number">1000000</span>):
        result += math.sqrt(i * x)
    <span class="hljs-keyword">return</span> result

data_list = list(range(<span class="hljs-number">1</span>, <span class="hljs-number">21</span>))

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">run_sequential</span>():</span>
    start = time.time()
    [heavy_computation(x) <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> data_list]
    print(<span class="hljs-string">f"Sequencial: <span class="hljs-subst">{time.time() - start:<span class="hljs-number">.2</span>f}</span>s"</span>)

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">run_threading</span>():</span>
    start = time.time()
    <span class="hljs-keyword">with</span> concurrent.futures.ThreadPoolExecutor() <span class="hljs-keyword">as</span> executor:
        list(executor.map(heavy_computation, data_list))
    print(<span class="hljs-string">f"Threading: <span class="hljs-subst">{time.time() - start:<span class="hljs-number">.2</span>f}</span>s"</span>)

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">run_multiprocessing</span>():</span>
    start = time.time()
    <span class="hljs-keyword">with</span> concurrent.futures.ProcessPoolExecutor() <span class="hljs-keyword">as</span> executor:
        list(executor.map(heavy_computation, data_list))
    print(<span class="hljs-string">f"Multiprocessing: <span class="hljs-subst">{time.time() - start:<span class="hljs-number">.2</span>f}</span>s"</span>)

<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:
    print(<span class="hljs-string">"Iniciando Benchmark..."</span>)
    run_sequential()
    run_threading()
    run_multiprocessing()
</code></pre>
<hr />
<h3 id="heading-analise-dos-dados">Análise dos Dados</h3>
<p>Aqui estão os resultados obtidos:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1768426067812/dea5d6ef-0ede-4de5-84e1-f162a69bf27c.png" alt class="image--center mx-auto" /></p>
<blockquote>
<p>Output do terminal mostrando os tempos de execução</p>
</blockquote>
<p>Vamos visualizar isso em um gráfico para entender a magnitude da otimização:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1768426097312/f08a85d9-eedf-4c2f-a376-031b4475496d.png" alt class="image--center mx-auto" /></p>
<blockquote>
<p>Comparação de tempo de execução (quanto menor, melhor)</p>
</blockquote>
<p>Também capturei o uso da CPU durante a execução do <strong>Sequencial, Threading e Multiprocessing</strong>. Perceba como todos os núcleos lógicos foram acionados para dividir a carga de trabalho:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1768426186905/08da0341-bd3c-4d2b-bd3d-08a78f2c74d3.gif" alt class="image--center mx-auto" /></p>
<blockquote>
<p>CPU chegando a 100% em todos os núcleos durante o Multiprocessing</p>
</blockquote>
<h3 id="heading-tabela-de-performance">Tabela de Performance</h3>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Método</strong></td><td><strong>Tempo</strong></td><td><strong>Observação Técnica</strong></td></tr>
</thead>
<tbody>
<tr>
<td>Sequencial</td><td>1.32s</td><td>Baseline (padrão).</td></tr>
<tr>
<td>Threading</td><td>1.62s</td><td><strong>Pior que o sequencial!</strong> O <em>overhead</em> de gerenciar threads somado ao GIL tornou o código mais lento.</td></tr>
<tr>
<td>Multiprocessing</td><td>0.44s</td><td><strong>3x mais rápido.</strong> Usou todos os núcleos da CPU para dividir o trabalho.</td></tr>
</tbody>
</table>
</div><hr />
<h2 id="heading-conclusao-qual-ferramenta-escolher">Conclusão: Qual ferramenta escolher?</h2>
<p>Como engenheiros, nosso papel não é apenas fazer o código funcionar, mas escolher a arquitetura correta para o problema.</p>
<ol>
<li><p><strong>Use Threading (ou AsyncIO) quando:</strong> O problema for <strong>I/O Bound</strong>. Exemplos: Web Scraping, chamadas de API, leitura de arquivos, conexões de banco de dados. O tempo é gasto "esperando" respostas, então o GIL não atrapalha.</p>
</li>
<li><p><strong>Use Multiprocessing quando:</strong> O problema for <strong>CPU Bound</strong>. Exemplos: Processamento de imagens, análise de dados massiva, criptografia, Machine Learning. Você precisa de força bruta computacional.</p>
</li>
</ol>
<p>Dominar o comportamento do hardware por trás do código é o que diferencia um programador de um engenheiro de software.</p>
<p>Você já teve problemas com o GIL em seus projetos? Deixe nos comentários como você resolveu!</p>
]]></content:encoded></item></channel></rss>