Python 3.13
Conteúdo
Ontem saiu o Python 3.13, uma das versões mais aguardadas do interpretador. A principal atração para mim sempre foi a possibilidade de rodar código em Python sem o GIL. O GIL, ou Global Interpreter Lock, assombrou o Python por muito tempo e sempre foi motivo de muitas discussões.
Há muito tempo vem se tentando remover o GIL do interpretador. Mas o que ele atrapalha? Quando rodamos um código com múltiplos threads em Python, o GIL garante que as estruturas comuns do interpretador estavam protegidas entre estes threads, ou seja, contra problemas de concorrência. Várias tentativas foram feitas, mas todas deixavam o Python mais lento ou só funcionavam em casos específicos. Um rant do Guido - It isn’t Easy to Remove GIL em resposta a este post Data Services and Integration, An open letter to Guido van Rossum: Mr Rossum, tear down that GIL!. Nada melhor que a PEP-703 para entender como estas conversas acabaram. Na realidade, não acabaram, o GIL pode ser ativado ou desativado e cada utilizador pode escolher qual versão do interpretador quer usar. Nem tudo são flores, pois várias bibliotecas ainda precisam de mais tempo para suportar esta opção e mesmo para estabilizarem seus códigos.
Você pode instalar o Python 3.13 e rodar o código abaixo para ver como ele funciona. Se sua distribuição Linux ainda não disponibilizar a versão 3.13, você pode experimentar usando Docker, compilar com pyenv e dentro de alguns dias usando o uv
. Para Mac e Windows, basta baixar os instaladores no site oficial python.org.
Como saber em qual interpretador você está?#
Primeiro, baixe o Python 3.13 e rode o instalador. No caso do Windows, escolha customizar a instalação e a opção que instala o Python3.13t.
Após instalar o Python 3.13, você pode verificar qual versão está usando, chamando o interpretador na linha de comandos.
O Python 3.13 normal não exibe a palavra experimental após a versão.
> python
Python 3.13.0 (tags/v3.13.0:60403a5, Oct 7 2024, 09:38:07) [MSC v.1941 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
No Windows e no Mac, os executáveis da versão sem GIL são nomeados diferentemente. No Windows, você usa python3.13t
para chamar a versão sem GIL.
> python3.13t
Python 3.13.0 experimental free-threading build (tags/v3.13.0:60403a5, Oct 7 2024, 09:53:29) [MSC v.1941 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
Veja que as palavras experimental free-threading aparecem após o número da versão.
No Linux, faça:
PYTHON_GIL=1 python
ou
python -X gil=0
Claro, após instalar o Python 3.13 e adaptar o comando para como você chama o interpretador. Provavelmente algo com python3.13
.
Um pequeno teste#
Vamos rodar este pequeno programa de teste para verificar as diferenças entre as versões 3.13 com e sem GIL. Ele gera uma pequena carga de processamento e a executa com e sem threads. O tempo de cada execução é exibido no final de cada execução. O programa detecta quantos cores você tem no sistema. Você pode aumentar o valor de CARGA
se rodar muito rápido no seu computador.
import time
import threading
import multiprocessing
import contextlib
from rich import print
CARGA = 10_000_000
def trabalho(name):
print(f" + Trabalho {name} iniciando")
z = 0
for i in range(CARGA):
z += i
print(f" - Trabalho {name} acabando")
@contextlib.contextmanager
def cronometro(mensagem):
print(mensagem)
start_time = time.time()
yield
end_time = time.time()
print(f"Tempo: {end_time - start_time}")
def com_threads():
threads = []
for i in range(multiprocessing.cpu_count()):
threads.append(threading.Thread(target=trabalho, args=(i,)))
for thread in threads:
thread.start()
for thread in threads:
thread.join()
def sem_threads():
for z in range(multiprocessing.cpu_count()):
trabalho(z)
if __name__ == "__main__":
with cronometro("Com threads"):
com_threads()
with cronometro("Sem threads"):
sem_threads()
Resultados com o Python 3.13 normal#
Resultados com o Python 3.13 No GIL#
Comparando#
Python | Com threads | Sem Threads |
---|---|---|
3.13 | 8.16193 | 8.50603 |
3.13t | 0.84548 | 9.50476 |
3.12 | 9.20192 | 8.78016 |
A versão 3.13t é a NOGIL e a 3.13 a versão normal. Todos os tempos em segundos.
Quando comparamos a velocidade entre a parte “Com threads” do programa entre as versões 3.13t e 3.13, a diferença de desempenho é enorme. Se você abrir o medidor de desempenho do seu computador, deve ver todos os cores sendo usados. Se seu computador for muito rápido, altere a CARGA
no programa para ver o circo pegar fogo :-D.
Porém, veja que na versão “Sem Threads”, o interpretador 3.13t foi mais lento que o 3.13 normal.
Observe também que o interpretador 3.12 foi mais lento que o 3.13 na tarefa “Sem Threads” e mais lento que ambos na versão “Com thread”.
Conclusão#
A versão 3.13 é um avanço nos interpretadores Python, não só pela opção de GIL/NOGIL, mas por dar uma esperança a várias bibliotecas e cargas de trabalho que realmente precisavam de threads. Embora os resultados da execução sequencial ainda não sejam melhores que a da versão tradicional, com GIL, as portas para otimizações estão abertas. Precisamos também esperar que as bibliotecas comecem a publicar versões compatíveis com a 3.13 e com suporte ao interpretador Python 3.13 NOGIL.
A versão 3.13 traz também um JIT simples, que pode melhorar muito no futuro e é outra otimização promissora no interpretador. Agora que está na versão principal, com certeza, a comunidade vai enviar mais código para melhorar e deixar o JIT mais rápido. Quem sabem em pouco tempo chegaremos ao nível do pypy.
Além disso, o time de desenvolvedores do Python conseguiu um compromisso entre testar novas funcionalidades para casos especiais, sem quebrar a compatibilidade com a versão padrão, dando mais tempo para que o código mature e seja testado por mais projetos e desenvolvedores.