|
| 1 | ++++ |
| 2 | +date = '2025-10-08T20:00:00-03:00' |
| 3 | +draft = false |
| 4 | +hiddenFromHomePage = false |
| 5 | +title = 'Async/Await a fondo' |
| 6 | +description = 'Una guía práctica para entender qué hace el compilador de Rust cuando usamos async/await, y cómo escribir un runtime asincrónico desde cero.' |
| 7 | +tags = ["rust", "async", "await", "concurrencia", "runtimes", "presentacion", "video"] |
| 8 | +categories = ["Proyectos", "Eventos"] |
| 9 | ++++ |
| 10 | + |
| 11 | +# Async a fondo: Cómo funciona async/await en Rust desde cero |
| 12 | + |
| 13 | +El pasado 08 de octubre de 2025 se llevó a cabo un nuevo encuentro de la comunidad de Rust, donde Jorge Prendes, presentó qué hace realmente `async fn`, cómo se implementa el trait `Future`, y cómo un runtime como Tokio ejecuta nuestras tareas concurrentes. |
| 14 | + |
| 15 | +--- |
| 16 | + |
| 17 | +## Presentación |
| 18 | + |
| 19 | +En esta presentación, Jorge Prendes nos va mostrando cómo se construye un async runtime desde cero, deteniéndose y explicando cada detalle para que podamos entender a fondo qué sucede cuando ejecutamos funciones asincrónas. |
| 20 | + |
| 21 | +{{< youtube fbM_IP0VFiA >}} |
| 22 | + |
| 23 | +--- |
| 24 | + |
| 25 | +## Descargar las slides |
| 26 | + |
| 27 | +[**📋 Descargar slides de la presentación (PDF)**](/slides/async-await.pdf) |
| 28 | + |
| 29 | +Las slides incluyen: |
| 30 | + |
| 31 | +- Por qué construir un async runtime desde cero. |
| 32 | +- Explicación de cómo es la anatomia de una función async. |
| 33 | +- Explicación del trait `Future` y los wakers. |
| 34 | +- Qué hacen los runtimes profesionales. |
| 35 | + |
| 36 | +--- |
| 37 | + |
| 38 | +## De `fn` a `async fn` |
| 39 | + |
| 40 | +A primera vista, usar `async fn` parece mágico: marcamos una función con `async`, agregamos `.await` y el código “funciona”. |
| 41 | +Sin embargo, un `async fn` no devuelve el valor directamente, sino una estructura que implementa el trait [`Future`](https://doc.rust-lang.org/std/future/trait.Future.html). |
| 42 | + |
| 43 | +El compilador transforma automáticamente la función en un tipo anónimo que implementa `Future`, con un método `poll` que controla su avance. |
| 44 | +Esto significa que *`async fn` es azúcar sintáctica para una máquina de estados que el compilador genera automáticamente.* |
| 45 | +Cada punto de suspensión (`await`) se convierte internamente en una transición de estado dentro de esa máquina. |
| 46 | + |
| 47 | +--- |
| 48 | + |
| 49 | +## El trait `Future` |
| 50 | + |
| 51 | +El corazón del modelo asincrónico de Rust es el trait `Future`, que define cómo una tarea avanza hacia su resultado final. |
| 52 | +Su método `poll` devuelve: |
| 53 | +- `Poll::Ready(val)` cuando el futuro ha completado su trabajo, o |
| 54 | +- `Poll::Pending` si todavía no puede continuar y necesita ser reintentado más adelante. |
| 55 | + |
| 56 | +Cada `Future` debe garantizar que, si devuelve `Pending`, notificará al *runtime* cuando esté listo para avanzar. |
| 57 | +Esa notificación se realiza mediante un objeto `Waker` que forma parte del contexto (`Context`) de ejecución. |
| 58 | + |
| 59 | +En términos conceptuales, un `Future` es un proceso cooperativo: no se ejecuta por sí mismo, sino que el runtime lo invoca repetidamente hasta que devuelve un valor final. |
| 60 | + |
| 61 | +--- |
| 62 | + |
| 63 | +## Construyendo un runtime mínimo |
| 64 | + |
| 65 | +Rust no ejecuta funciones `async fn` automáticamente: requiere un *runtime* que gestione la ejecución de los futuros. |
| 66 | +Un runtime es, esencialmente, un *scheduler* que mantiene una cola de tareas y llama a `poll` sobre cada una cuando hay progreso disponible. |
| 67 | + |
| 68 | +Un runtime básico puede implementarse en pocas líneas: un bucle que invoca `poll`, y que espera eventos externos (por ejemplo, mediante un canal o un selector del sistema operativo). |
| 69 | +Cuando un `Future` devuelve `Pending`, el runtime suspende su ejecución y se bloquea hasta que algún `Waker` lo despierte. |
| 70 | + |
| 71 | +De esta forma, se logra concurrencia sin necesidad de hilos múltiples, aprovechando un único hilo cooperativo que gestiona múltiples tareas de manera eficiente. |
| 72 | + |
| 73 | +--- |
| 74 | + |
| 75 | +## El papel del `Waker` |
| 76 | + |
| 77 | +El `Waker` es el mecanismo mediante el cual los futuros notifican al runtime que están listos para continuar. |
| 78 | +Cuando un `Future` devuelve `Poll::Pending`, registra un `Waker` para que, cuando haya nuevo trabajo disponible, pueda invocar `wake_by_ref` y alertar al runtime. |
| 79 | + |
| 80 | +Runtimes como Tokio, Smol o Embassy implementan este concepto con diferentes estrategias: |
| 81 | +- **Tokio** utiliza mecanismos del sistema operativo como `epoll` o `kqueue` para gestionar miles de operaciones I/O en un solo hilo. |
| 82 | +- **Smol** emplea un *thread pool* ligero que aprovecha primitivas de la biblioteca estándar. |
| 83 | +- **Embassy** está diseñado para entornos sin sistema operativo (bare metal), y usa un *Hardware Abstraction Layer (HAL)* para interactuar directamente con el hardware. |
| 84 | + |
| 85 | +En todos los casos, el principio es el mismo: el `Waker` conecta los futuros con el scheduler que los controla. |
| 86 | + |
| 87 | +--- |
| 88 | + |
| 89 | +## Demo interactiva |
| 90 | + |
| 91 | +Puedes explorar una implementación práctica del modelo explicado en Rust Playground: |
| 92 | + |
| 93 | +- [Versión básica](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=b51f63e714ab80cf109a443bfcbc9c46) |
| 94 | +- [Versión avanzada](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=c244fef8ad8aa124058234f63c7d096e) |
| 95 | + |
| 96 | +La versión básica ejecuta tareas secuenciales, mientras que la avanzada crea múltiples futuros que se ejecutan en paralelo sobre el mismo runtime. |
| 97 | + |
| 98 | +--- |
| 99 | + |
| 100 | +## Conclusiones |
| 101 | + |
| 102 | +- Un `async fn` es una transformación sintáctica que genera una máquina de estados que implementa `Future`. |
| 103 | +- Los runtimes asincrónicos como Tokio o Smol son *schedulers* que ejecutan y reactivan futuros basados en eventos del sistema. |
| 104 | +- Implementar un runtime simple ayuda a comprender los fundamentos del modelo asincrónico de Rust. |
| 105 | +- Comprender `poll`, `Context` y `Waker` permite escribir código más eficiente, predecible y compatible con runtimes existentes. |
| 106 | + |
| 107 | +Detrás de `async/await` no hay magia: solo **transformaciones deterministas y un modelo explícito de concurrencia**. |
| 108 | +Entender estos conceptos es clave para dominar la programación asincrónica en Rust. |
| 109 | + |
| 110 | +--- |
| 111 | + |
| 112 | +## Referencias |
| 113 | + |
| 114 | +- [Documentación oficial de `Future`](https://doc.rust-lang.org/std/future/trait.Future.html) |
| 115 | +- [Tutorial oficial de Tokio](https://tokio.rs/tokio/tutorial/async#) |
| 116 | +- [Smol runtime](https://github.com/smol-rs/smol) |
| 117 | +- [Embassy para entornos embebidos](https://github.com/embassy-rs/embassy) |
| 118 | +- [Proyecto Hyperlight](https://github.com/hyperlight-dev/hyperlight) |
| 119 | + |
| 120 | +--- |
| 121 | + |
| 122 | +## Comunidad |
| 123 | + |
| 124 | +La comunidad de Rust es uno de los pilares del lenguaje. Hay múltiples espacios de participación, tanto virtuales como presenciales: |
| 125 | + |
| 126 | +### Conferencias |
| 127 | + |
| 128 | +- [RustWeek](https://rustweek.org/) |
| 129 | +- [RustConf](https://rustconf.com/) |
| 130 | +- [EuroRust](https://eurorust.eu/) |
| 131 | +- [RustNation UK](https://www.rustnationuk.com/) |
| 132 | + |
| 133 | +### Comunidad Online |
| 134 | + |
| 135 | +- [Rust en español - Telegram](https://t.me/rust_lang_es) |
| 136 | +- [Foro oficial](https://users.rust-lang.org/) |
| 137 | +- [Subreddit r/rust](https://www.reddit.com/r/rust/) |
| 138 | +- [Canal de soporte en Zulip](https://rust-lang.zulipchat.com/) |
| 139 | +- [Discord de la comunidad](https://discord.gg/rust-lang-community) |
0 commit comments