Racional de Design Assíncrono para SDKs
Resumo Executivo
Cada SDK implementa padrões assíncronos otimizados para seu ecossistema:
| SDK | Padrão | Racional |
|---|---|---|
| TypeScript | Async/await real | Promises nativas do JS, padrão web |
| Python | Bloqueante + padrões asyncio | Evita conflitos de versão do PyO3, soluções documentadas |
| Swift | Bloqueante + wrapper Task | Alinha com a Concorrência do Swift, simples e comprovado |
Todos os três alcançam I/O não bloqueante em seus respectivos ecossistemas através de meios idiomáticos da linguagem.
TypeScript: ✅ Totalmente Assíncrono
Implementação
pub async fn get_status(&self) -> Result<String, JsValue>
Compilado para WASM com wasm-bindgen-futures → Promises JavaScript.
Por que funciona
- Promessa Nativa do JavaScript: Todo async no JS retorna Promise<T>
- Fronteira WASM:
wasm-bindgenlida com a conversão de Promise automaticamente - Sem Conflitos de Versão:
wasm-bindgen(0.2) é estável, sem problemas como o PyO3 - Leve: Promises são abstrações de custo zero em mecanismos JS modernos
Uso
const status = await client.getStatus(); // Natural, idiomático
Trade-offs
| Aspecto | Trade-off |
|---|---|
| Eficiência | ✅ Overhead zero (promise nativa) |
| Simplicidade | ✅ Único caminho de implementação |
| Compatibilidade | ✅ Todos os navegadores + Node.js |
Python: ⏳ Bloqueante + Guia de Integração Async
Implementação
def get_status(&self) -> str:
return self.rt.block_on(self.client.get_status()).await
Método Python síncrono usando um runtime Tokio oculto.
Por que NÃO Async Real (pyo3-asyncio)
Problema de Conflito de Versão:
pyo3 = 0.21
pyo3-asyncio = 0.20 ← requer pyo3 = 0.20
Conflito! ❌
Caminho de Atualização Bloqueado:
- PyO3 0.21 tem nova API (suporte a corrotinas)
- pyo3-asyncio 0.20 ainda não atualizou
- Única solução: fazer o downgrade do PyO3 para 0.20 (perde novos recursos)
Correção Esperada: PyO3 0.22+ (Q3-Q4 2026)
- pyo3-asyncio atualizará para 0.22
- Sem mais conflitos de versão
- Async real possível
Solução Atual: asyncio.to_thread()
Para contextos assíncronos, use o padrão de integração asyncio:
import asyncio
from paebiru import PaebiruClient
client = PaebiruClient("http://...")
async def main():
# Chamada não bloqueante para função bloqueante
status = await asyncio.to_thread(client.get_status)
Por que funciona
- Seguro para GIL: O pool de threads está ciente do GIL
- Não bloqueante: O loop de eventos continua enquanto a thread executa
- Padrão: Embutido no Python 3.9+
- Sem Dependências: Sem conflitos de versão
Performance
- Inicialização da thread: ~0.5ms (reutilizada com executor)
- I/O de rede: 1-5ms (fator dominante)
- Memória: ~8MB por thread
Trade-offs
| Aspecto | Trade-off |
|---|---|
| Eficiência | ⏳ Usa thread do SO (não leve) |
| Simplicidade | ⏳ Requer wrapper asyncio.to_thread() |
| Compatibilidade | ✅ Python 3.9+ (3.7-3.8 usam executor) |
| Confiabilidade | ✅ Sem conflitos de versão |
Caminho de Migração
Agora (PyO3 0.21):
# Solução alternativa para async
status = await asyncio.to_thread(client.get_status)
Futuro (PyO3 0.22+):
# Async nativo (planejado)
client_async = AsyncPaebiruClient("http://...")
status = await client_async.get_status()
Swift: Bloqueante + Swift Concurrency
Implementação
func getStatus() throws -> String
Método síncrono usando runtime Tokio oculto.
Por que Bloqueante (Não Swift async nativo)
Racional do Trade-off:
-
Simplicidade de Implementação
- Bloqueante: 150 linhas de FFI
- Async nativo: Requer wrappers async/await personalizados
- Bridging Tokio ↔ Swift async complexo
-
Alinha-se com o Modelo de Concorrência do Swift
- O
async/awaitdo Swift envolve operações síncronas - O usuário envolve o SDK bloqueante em
Task { }:Task { let status = try await Task.detached(priority: .userInitiated) { try node.getStatus() }.value }
- O
-
Padrão Comprovado
- Muitas bindings Rust FFI usam isso (especialmente iOS)
- Familiar para desenvolvedores Swift
- Baixa fricção para adoção
Integração com Swift Concurrency
Wrapper para Concorrência:
actor PaebiruNodeAsync {
private let node: PaebiruNode
init(baseUrl: String) throws {
self.node = try PaebiruNode(baseUrl: baseUrl)
}
nonisolated func getStatus() async throws -> String {
return try Task.detached(priority: .userInitiated) {
try node.getStatus()
}.value
}
}
Uso
let node = try PaebiruNodeAsync(baseUrl: "http://...")
Task {
let status = try await node.getStatus()
print(status)
}
Trade-offs
| Aspecto | Trade-off |
|---|---|
| Eficiência | ⏳ Troca de contexto de Task (leve) |
| Simplicidade | ✅ SDK simples, wrapper simples |
| Compatibilidade | ✅ Swift 5.5+ (todos os iOS/macOS modernos) |
| Natividade | ⏳ Não é Swift async nativo (wrapper necessário) |
Análise Comparativa
Ranking de Eficiência
- TypeScript (✅ Melhor): Promises de custo zero, nativo
- Swift (⏳ Bom): Troca de contexto de Task leve
- Python (⏳ Aceitável): Overhead de thread do SO, mas aceitável para I/O-bound
Ranking de Simplicidade
- Python (✅ Melhor): Chamadas bloqueantes diretas
- TypeScript (✅ Bom): Async/await direto
- Swift (⏳ Regular): Requer wrapper Task
Ranking de Confiabilidade
- Python (✅ Melhor): Sem conflitos de versão, padrões documentados
- TypeScript (✅ Melhor): Ecossistema
wasm-bindgenestável - Swift (✅ Bom): Sem dependências assíncronas externas
Matriz de Decisão
Ao escolher o padrão assíncrono por linguagem:
| Critério | Importante para |
|---|---|
| Suporte Nativo | Web (TS: Promises), Sistema (Swift: concurrency), Runtime (Python: asyncio) |
| Estabilidade de Versão | Bibliotecas (conflitos PyO3), ecossistemas (npm estável, crates.io estável) |
| UX do Desenvolvedor | Curva de aprendizado, boilerplate, fricção de integração |
| Performance | I/O-bound (rede), compute-bound, tempo real |
Resumo
Todos os três padrões são corretos para seu ecossistema:
- TS: Usa o que o JavaScript fornece nativamente
- Python: Usa o modelo assíncrono do Python + contorna conflitos de biblioteca
- Swift: Usa Swift Concurrency + bridging pragmático
Futuro: Interface Assíncrona Unificada
Quando o PyO3 0.22+ estabilizar (Q3-Q4 2026):
# Async real, sem conflitos
from paebiru import AsyncPaebiruClient
client = AsyncPaebiruClient("http://...")
status = await client.get_status() # Nativo!
Então todos os três SDKs terão:
- ✅ Async nativo da linguagem
- ✅ Zero boilerplate
- ✅ Performance otimizada
Isso unifica a DX mantendo implementações idiomáticas da linguagem.
Recomendações
Para Código Síncrono
- Python: Use
PaebiruClientdiretamente - TypeScript: Use
awaitde nível superior (ou Promise.then()) - Swift: Use
PaebiruNodediretamente
Para Código Assíncrono
- Python:
await asyncio.to_thread(client.method) - TypeScript:
await client.method()(nativo) - Swift: Envolva em
Task { }ou actor
Para Alta Concorrência
- Python:
asyncio.gather()com executor de thread - TypeScript:
Promise.all()(natural) - Swift:
async letou concorrência estruturada
Para Produção
- Todos os três padrões estão prontos para produção
- Recomendado seguir as convenções da linguagem
- Documentar padrões assíncronos no onboarding do projeto