Python Free-Threaded: Adeus ao GIL?

Como a build free-threaded do CPython (PEP 703, oficialmente suportada desde o Python 3.14) remove o Global Interpreter Lock e permite paralelismo real de CPU entre threads Python.

Desde a versão 1.0, o CPython usa o GIL (Global Interpreter Lock): um mutex único que garante que apenas uma thread execute bytecode Python por vez, mesmo em máquinas com vários núcleos. Isso simplifica o interpretador e protege estruturas internas de condições de corrida, mas também significa que código Python multithread nunca conseguiu paralelismo real de CPU — só ajuda quando as threads passam a maior parte do tempo esperando I/O. O Python free-threaded (PEP 703) é uma build alternativa do CPython que remove o GIL, permitindo que múltiplas threads executem bytecode Python simultaneamente em núcleos diferentes.

O problema que o GIL sempre causou

Um programa que usa threading para dividir trabalho pesado de CPU entre threads não ganha velocidade proporcional aos núcleos disponíveis, porque o GIL serializa a execução:

import threading
import time

def contar(n):
    while n > 0:
        n -= 1

inicio = time.perf_counter()
threads = [threading.Thread(target=contar, args=(30_000_000,)) for _ in range(4)]
for t in threads:
    t.start()
for t in threads:
    t.join()
print(f"{time.perf_counter() - inicio:.2f}s")

Na build padrão do CPython, esse código com 4 threads não fica muito mais rápido do que rodar as quatro contagens em sequência — o GIL alterna entre as threads, mas só uma roda bytecode por vez. Por isso, o padrão histórico para paralelismo real em Python sempre foi multiprocessing, que contorna o GIL criando processos separados, com o custo de serialização entre eles (pickle) e maior uso de memória.

Como funciona a build free-threaded

A partir do Python 3.13, o instalador oficial passou a oferecer uma build experimental sem o GIL, identificada pelo sufixo t (de threading). Para usá-la é preciso instalar esse binário específico — o Python padrão continua com o GIL ativado:

python3.13t --version
# Python 3.13.x (com suporte a free-threading habilitado)

Internamente, a build free-threaded substitui o lock único por mecanismos mais finos: contagem de referências thread-safe (biased reference counting) e locks específicos por objeto, em vez de um lock global para o interpretador inteiro. O resultado é que o mesmo código de contagem acima, rodado no python3.13t, de fato distribui o trabalho entre os núcleos disponíveis e reduz o tempo total proporcionalmente ao número de threads.

Verificando em runtime se o GIL está desabilitado

O módulo sys ganhou uma forma de checar isso programaticamente, útil para logs de diagnóstico ou testes condicionais:

import sys

if hasattr(sys, "_is_gil_enabled"):
    print("GIL ativo:", sys._is_gil_enabled())
else:
    print("Build sem suporte a free-threading")

Uma extensão C ainda não adaptada para o modo free-threaded pode reativar o GIL automaticamente ao ser importada, como medida de segurança — nesse caso o programa continua funcionando, só perde o ganho de paralelismo enquanto aquela extensão estiver carregada.

Exemplo prático: processamento paralelo de CPU

Dividir uma lista grande de trabalho entre threads, sem recorrer a processos separados, passa a fazer sentido para tarefas de CPU:

from concurrent.futures import ThreadPoolExecutor

def eh_primo(n):
    if n < 2:
        return False
    return all(n % d for d in range(2, int(n**0.5) + 1))

numeros = range(2, 200_000)
with ThreadPoolExecutor(max_workers=8) as executor:
    primos = list(executor.map(eh_primo, numeros))

print(sum(primos), "números primos encontrados")

No CPython padrão, esse ThreadPoolExecutor não traria ganho de desempenho relevante para uma tarefa desse tipo, dominada por CPU. Numa build free-threaded, com eh_primo sem dependências externas, o trabalho é de fato paralelizado entre as 8 threads.

Quando usar

Cuidados

Remover o GIL expõe código que sempre dependeu dele implicitamente para evitar condições de corrida — estruturas de dados compartilhadas sem lock explícito, que "funcionavam por acaso" porque o GIL serializava tudo, podem se comportar de forma diferente na build free-threaded. Extensões em C que usam a API C do CPython diretamente também precisam ser adaptadas (a maioria das bibliotecas populares ainda está em processo de suporte). Até o Python 3.13, a build free-threaded era experimental e não era a distribuída por padrão; é preciso instalá-la explicitamente.

Compatibilidade

A PEP 703 introduziu a build free-threaded como experimental no Python 3.13 (outubro de 2024). A PEP 779 promoveu esse suporte a oficialmente suportado a partir do Python 3.14 (outubro de 2025) — deixou de ser experimental, mas ainda não é a build padrão instalada. O overhead em código single-thread, que era de cerca de 40% nas primeiras versões, caiu para a faixa de 5-10% no Python 3.14.

documentação oficial

Conclusão

O free-threading não torna o Python multithread mais rápido em todos os casos — código dominado por I/O já se beneficiava do GIL sendo liberado durante esperas — mas resolve o problema histórico de paralelismo real de CPU, que antes só o multiprocessing endereçava. Ainda é uma mudança em transição, com bibliotecas se adaptando, mas já dá para experimentar com o binário python3.13t ou python3.14t hoje.

Tecnologia:
python

Deixe seu Comentário!

Dúvida, sugestão ou só um "valeu!" — tudo é bem-vindo por aqui.

Comentário
Nome
Email
lock Seu e-mail não será publicado.