🧵 Programação Assíncrona e Metaprogramação em Python vs Ruby
Python vs Ruby — Assíncrono e Metaprogramação
Este documento compara as abordagens de Python e Ruby para dois temas poderosos: programação assíncrona e metaprogramação.
⚙️ Programação Assíncrona
Python com asyncio
import asyncio
async def tarefa():
print("Início")
await asyncio.sleep(1)
print("Fim")
asyncio.run(tarefa())
- Nativo desde o Python 3.5 (
async
,await
) - Cancelamento com
.cancel()
- Timeout com
asyncio.wait_for()
- Execução paralela com
asyncio.gather()
- Suporte a
async generators
Ruby com async
(gem)
require 'async'
Async do
task1 = Async { sleep 2; puts "Task 1 done" }
task2 = Async { sleep 1; puts "Task 2 done" }
end
- Utiliza Fibers (não threads)
- Controle via escopos de tarefa
- Cancelamento com
task.stop
- Timeout com
Async::Timeout
- Leve, elegante, mas exige gems externas
Cancelamento de Tarefa em Ruby
require 'async'
Async do |task|
child = task.async { sleep 5; puts "não verá isso" }
sleep 1
child.stop # Cancela
end
Timeout em Ruby
require 'async'
require 'async/timeout'
Async do
Async::Timeout.timeout(2) do
sleep 5
end
rescue Async::TimeoutError
puts "Tempo excedido!"
end
🧠 Metaprogramação
Python
def criar_classe():
return type('NovaClasse', (), {'diga_oi': lambda self: print("Oi")})
cls = criar_classe()
obj = cls()
obj.diga_oi()
- Criação de classes com
type()
- Metaclasses via
__new__
- Descriptors com
__get__
,__set__
- Manipulação de AST (
ast
,inspect
) - Monkey patching e introspecção
Ruby
class Pessoa
define_method(:diga_oi) { puts "Oi!" }
end
Pessoa.new.diga_oi
- Tudo é objeto (incluindo classes e métodos)
- Métodos dinâmicos com
define_method
method_missing
para interceptação- Avaliação dinâmica com
eval
,instance_eval
Module#prepend
,alias_method
para alteração de comportamento
Ruby: method_missing
class Logger
def method_missing(metodo, *args)
puts "Chamou #{metodo} com #{args.inspect}"
end
end
Logger.new.salvar("teste")
Ruby: introspecção e reflexão
class Produto
attr_accessor :nome
end
p = Produto.new
p.methods.include?(:nome) # true
🕐 Cancelamento de Tarefas
Permite interromper uma tarefa que não precisa mais ser executada. Útil em sistemas reativos ou que precisam otimizar recursos.
import asyncio
async def tarefa_longa():
print("A iniciar tarefa longa")
try:
await asyncio.sleep(10)
except asyncio.CancelledError:
print("Tarefa longa cancelada")
raise
print("Tarefa longa concluída")
return "Resultado da tarefa longa"
async def main():
tarefa = asyncio.create_task(tarefa_longa())
await asyncio.sleep(2)
print("A cancelar tarefa")
tarefa.cancel()
try:
await tarefa
except asyncio.CancelledError:
print("Tarefa principal: tarefa foi cancelada")
if __name__ == "__main__":
asyncio.run(main())
Explicação:
create_task()
agenda uma coroutine para rodar em segundo plano.cancel()
emite um sinal de cancelamento.- A exceção
CancelledError
permite capturar esse cancelamento e reagir apropriadamente.
⏱️ Timeouts com asyncio.wait_for
Controla o tempo de espera de uma coroutine. Se ela demorar demais, é cancelada automaticamente.
async def tarefa_demorada():
await asyncio.sleep(5)
return "Resultado"
async def main():
try:
resultado = await asyncio.wait_for(tarefa_demorada(), timeout=2)
print(f"Resultado: {resultado}")
except asyncio.TimeoutError:
print("Tempo de espera excedido!")
Explicação:
- Útil para prevenir travamentos ou lentidão em chamadas de rede ou I/O.
TimeoutError
pode ser tratado como fallback ou retry.
⚡ Tratamento de Exceções em Corrotinas
Erros acontecem — e precisam ser capturados para não comprometer o loop de eventos.
async def tarefa_com_erro():
raise ValueError("Ocorreu um erro na tarefa")
async def main():
try:
await tarefa_com_erro()
except ValueError as e:
print(f"Erro capturado: {e}")
Explicação:
- Sempre trate exceções ao usar
await
para manter o controle da aplicação.
✨ Corrotinas dentro de Corrotinas
Permite criar fluxos assíncronos mais complexos e encadeados.
async def tarefa1():
print("Tarefa 1 iniciada")
await asyncio.sleep(1)
print("Tarefa 1 concluída")
return "Resultado 1"
async def tarefa2():
print("Tarefa 2 iniciada")
await asyncio.sleep(2)
print("Tarefa 2 concluída")
return "Resultado 2"
async def main():
resultado1 = await tarefa1()
resultado2 = await tarefa2()
print(f"Resultados: {resultado1}, {resultado2}")
Explicação:
- Cada coroutine pode aguardar outras, permitindo controle total da ordem de execução.
🌐 Async Generators
Geração assíncrona de valores — ideal para grandes volumes de dados ou streams.
async def gerar_numeros(maximo):
numero = 0
while numero < maximo:
yield numero
numero += 1
await asyncio.sleep(0.5)
async def main():
async for numero in gerar_numeros(5):
print(f"Número: {numero}")
Explicação:
yield
em conjunto comawait
permite produzir dados em tempo real sem bloquear a aplicação.
🔮 Dicas e Truques com asyncio
gather()
: executa várias tarefas ao mesmo tempo.to_thread()
: roda funções bloqueantes em uma thread separada.get_event_loop()
: acesso manual ao loop para controle fino.- Use bibliotecas assíncronas: como
aiohttp
,aiomysql
,aiosqlite
, etc.
⚖️ Comparativo Final
Conceito | Python | Ruby |
---|---|---|
Assíncrono nativo | ✅ asyncio | ⚠️ via gem (async, EventMachine) |
Cancelamento de tarefas | ✅ cancel(), try/except | ⚠️ task.stop, escopos manuais |
Timeout | ✅ wait_for() | ⚠️ Async::Timeout |
async generators |
✅ sim | ❌ não diretamente |
Criação dinâmica de classe | ✅ type() |
✅ define_method , class_eval |
Metaclasses | ✅ via type , __new__ |
✅ via Class.new , Module |
AST e introspecção | ✅ ast , inspect |
⚠️ introspecção limitada |
Monkey patching | ✅ sim | ✅ muito comum |
🧩 Conclusão
A combinação de programação assíncrona e metaprogramação representa o ápice da expressividade e controle sobre o fluxo e a estrutura de um programa — e tanto Python quanto Ruby oferecem abordagens poderosas, ainda que com focos diferentes.
🐍 Python:
- O
asyncio
provê uma estrutura robusta, eficiente e escalável para lidar com tarefas simultâneas, I/O não bloqueante e fluxos de controle altamente performáticos. - A metaprogramação com
type()
, metaclasses, descriptors e AST torna o Python uma linguagem introspectiva e dinâmica, excelente para automações, frameworks e DSLs controladas.
💎 Ruby:
- O Ruby brilha pela elegância e concisão. Com
define_method
,method_missing
,eval
eModule#prepend
, a metaprogramação se torna fluida e poderosa. - Para tarefas assíncronas, gems como
async
,eventmachine
ecelluloid
trazem capacidades equivalentes, especialmente úteis para servidores e aplicações reativas.
🧠 Em resumo:
- Se seu foco é concorrência com controle preciso do loop de eventos, Python entrega isso de forma mais direta.
- Se você deseja criar DSLs, estruturas dinâmicas, ou modificar comportamento de código com leveza, Ruby é imbatível na metaprogramação.
Ambas linguagens são ferramentas de alto nível — e saber usá-las com consciência pode transformar a forma como você escreve e entende software.