<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:media="http://search.yahoo.com/mrss/"><channel><title>Python Async · DacaCode &lt;/&gt;</title><link>https://blog.dacadev.com/series/python-async/</link><description>Blog de tecnología, programación y electrónica, para compartir conocimientos, experiencias y tutoriales con este apasionante mundo.</description><generator>Hugo</generator><language>es-CO</language><copyright>Copyright © 2026 DacaDev. All rights reserved.</copyright><lastBuildDate>Wed, 24 Jun 2026 00:00:00 -0500</lastBuildDate><atom:link href="https://blog.dacadev.com/series/python-async/index.xml" rel="self" type="application/rss+xml"/><image><url>https://blog.dacadev.com/images/blog-logo.png</url><title>DacaCode &lt;/&gt;</title><link>https://blog.dacadev.com/</link></image><item><title>aiohttp: Peticiones HTTP Concurrentes con asyncio</title><link>https://blog.dacadev.com/python/asyncio/aiohttp-peticiones-concurrentes/</link><pubDate>Wed, 24 Jun 2026 00:00:00 -0500</pubDate><guid>https://blog.dacadev.com/python/asyncio/aiohttp-peticiones-concurrentes/</guid><dc:creator>Dacadev</dc:creator><category>python</category><description>Aprende a hacer peticiones HTTP concurrentes con aiohttp y a coordinarlas con gather, as_completed y wait en asyncio para maximizar el rendimiento.</description><media:content url="https://blog.dacadev.com/images/python/asyncio/aiohttp/banner.png" medium="image" type="image/png"/><content:encoded>
&lt;details class="table-of-content "&gt;
 &lt;summary&gt;
 
 Tabla de Contenido
 
 &lt;/summary&gt;
 &lt;nav id="TableOfContents"&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#el-patrón-async-with-context-managers-asíncronos"&gt;El Patrón &lt;code&gt;async with&lt;/code&gt;: Context Managers Asíncronos&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#aiohttp-sesiones-y-connection-pooling"&gt;aiohttp: Sesiones y Connection Pooling&lt;/a&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#configurando-timeouts"&gt;Configurando Timeouts&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
 &lt;/li&gt;
 &lt;li&gt;&lt;a href="#la-trampa-del-await-secuencial"&gt;La Trampa del &lt;code&gt;await&lt;/code&gt; Secuencial&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#gather-recolectar-todos-los-resultados"&gt;&lt;code&gt;gather&lt;/code&gt;: Recolectar Todos los Resultados&lt;/a&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#manejo-de-excepciones-en-gather"&gt;Manejo de Excepciones en &lt;code&gt;gather&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
 &lt;/li&gt;
 &lt;li&gt;&lt;a href="#as_completed-procesar-a-medida-que-terminan"&gt;&lt;code&gt;as_completed&lt;/code&gt;: Procesar a Medida que Terminan&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#wait-control-fino-sobre-la-espera"&gt;&lt;code&gt;wait&lt;/code&gt;: Control Fino sobre la Espera&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#cuál-debo-usar"&gt;¿Cuál Debo Usar?&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#en-conclusión"&gt;En conclusión&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#referencias"&gt;Referencias&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
&lt;/nav&gt;
&lt;/details&gt;

&lt;p&gt;En el &lt;a href="https://blog.dacadev.com/python/asyncio/futures-awaitables-errores-comunes"



 


&gt;artículo anterior&lt;/a&gt; cerramos con una regla clave: nunca uses APIs bloqueantes como &lt;code&gt;requests&lt;/code&gt; dentro de una coroutine, porque bloquean el event loop. La alternativa asíncrona por excelencia para clientes HTTP es &lt;a href="https://docs.aiohttp.org/"




 target="_blank"
 


&gt;&lt;code&gt;aiohttp&lt;/code&gt;&lt;/a&gt;. En este artículo la pondremos en práctica y, más importante aún, veremos cómo coordinar &lt;strong&gt;cientos de peticiones concurrentes&lt;/strong&gt; con las tres APIs que &lt;code&gt;asyncio&lt;/code&gt; ofrece para esto: &lt;code&gt;gather&lt;/code&gt;, &lt;code&gt;as_completed&lt;/code&gt; y &lt;code&gt;wait&lt;/code&gt;.&lt;/p&gt;




 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Aprenderás a usar &lt;code&gt;aiohttp&lt;/code&gt; con sesiones y &lt;em&gt;connection pooling&lt;/em&gt;, a entender el patrón &lt;code&gt;async with&lt;/code&gt;, y a elegir entre &lt;code&gt;gather&lt;/code&gt;, &lt;code&gt;as_completed&lt;/code&gt; y &lt;code&gt;wait&lt;/code&gt; según necesites resultados ordenados, procesamiento incremental o control fino sobre la cancelación.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="el-patrón-async-with-context-managers-asíncronos"&gt;El Patrón &lt;code&gt;async with&lt;/code&gt;: Context Managers Asíncronos&lt;/h2&gt;
&lt;p&gt;Antes de tocar &lt;code&gt;aiohttp&lt;/code&gt; debemos entender el patrón sobre el que se construye. Un &lt;strong&gt;context manager síncrono&lt;/strong&gt; se define con &lt;code&gt;__enter__&lt;/code&gt; y &lt;code&gt;__exit__&lt;/code&gt; y nos permite adquirir y liberar recursos de forma segura con &lt;code&gt;with&lt;/code&gt;. Su equivalente asíncrono usa los métodos &lt;code&gt;__aenter__&lt;/code&gt; y &lt;code&gt;__aexit__&lt;/code&gt;, y se consume con &lt;code&gt;async with&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;La diferencia es que estos métodos son coroutines: pueden usar &lt;code&gt;await&lt;/code&gt; internamente para adquirir o liberar el recurso sin bloquear el event loop.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;class&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;ConnectedSocket&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#56b6c2;font-weight:bold"&gt;__init__&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;server_socket&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;_connection&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;None&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;_server_socket&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;server_socket&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#56b6c2;font-weight:bold"&gt;__aenter__&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;): &lt;span style="color:#7f848e"&gt;# 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;loop&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;get_event_loop&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;connection&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;address&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;await&lt;/span&gt; &lt;span style="color:#e06c75"&gt;loop&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;sock_accept&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;_server_socket&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;_connection&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;connection&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;_connection&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#56b6c2;font-weight:bold"&gt;__aexit__&lt;/span&gt;(&lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;exc_type&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;exc_val&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;exc_tb&lt;/span&gt;): &lt;span style="color:#7f848e"&gt;# 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;self&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;_connection&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;close&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;&lt;code&gt;__aenter__&lt;/code&gt; se ejecuta al entrar al bloque &lt;code&gt;async with&lt;/code&gt; y retorna el recurso (la conexión).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;__aexit__&lt;/code&gt; se ejecuta al salir del bloque —incluso si hay una excepción— y libera el recurso.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Esto es relevante porque, como veremos enseguida, tanto la sesión de &lt;code&gt;aiohttp&lt;/code&gt; como cada petición que hacemos son context managers asíncronos.&lt;/p&gt;
&lt;pre class="mermaid"&gt;sequenceDiagram
 participant C as Código (async with)
 participant CM as Context Manager
 C-&amp;gt;&amp;gt;CM: await __aenter__()
 Note over CM: adquiere el recurso (sin bloquear)
 CM--&amp;gt;&amp;gt;C: retorna el recurso
 Note over C: ejecuta el bloque async with
 C-&amp;gt;&amp;gt;CM: await __aexit__()
 Note over CM: libera el recurso
&lt;/pre&gt;

&lt;h2 id="aiohttp-sesiones-y-connection-pooling"&gt;aiohttp: Sesiones y Connection Pooling&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;aiohttp&lt;/code&gt;, y los clientes HTTP en general, se basan en el concepto de &lt;strong&gt;sesión&lt;/strong&gt;. Una &lt;code&gt;ClientSession&lt;/code&gt; mantiene abiertas varias conexiones que luego se reutilizan entre peticiones. Esto se conoce como &lt;strong&gt;connection pooling&lt;/strong&gt; y es fundamental para el rendimiento: crear una conexión TCP es costoso, así que reutilizar un pool reduce drásticamente esa sobrecarga.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;aiohttp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#e06c75"&gt;aiohttp&lt;/span&gt; &lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;ClientSession&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;fetch_status&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;session&lt;/span&gt;: &lt;span style="color:#e06c75"&gt;ClientSession&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;url&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;with&lt;/span&gt; &lt;span style="color:#e06c75"&gt;session&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;get&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;url&lt;/span&gt;) &lt;span style="color:#c678dd"&gt;as&lt;/span&gt; &lt;span style="color:#e06c75"&gt;result&lt;/span&gt;: &lt;span style="color:#7f848e"&gt;# 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;result&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;status&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;main&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;with&lt;/span&gt; &lt;span style="color:#e06c75"&gt;aiohttp&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;ClientSession&lt;/span&gt;() &lt;span style="color:#c678dd"&gt;as&lt;/span&gt; &lt;span style="color:#e06c75"&gt;session&lt;/span&gt;: &lt;span style="color:#7f848e"&gt;# 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;url&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;https://example.com&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;status&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;await&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fetch_status&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;session&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;url&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#98c379"&gt;f&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;Status para &lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e06c75"&gt;url&lt;/span&gt;&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt;: &lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e06c75"&gt;status&lt;/span&gt;&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;run&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;main&lt;/span&gt;())
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;&lt;code&gt;session.get(url)&lt;/code&gt; es un context manager asíncrono: dentro del bloque tenemos la respuesta; al salir, la conexión vuelve al pool.&lt;/li&gt;
&lt;li&gt;La sesión también se gestiona con &lt;code&gt;async with&lt;/code&gt;, garantizando que todas las conexiones se cierren correctamente al terminar.&lt;/li&gt;
&lt;/ol&gt;




 
 





 


&lt;div class="notice tip"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M15.362 5.214A8.252 8.252 0 0 1 12 21 8.25 8.25 0 0 1 6.038 7.047 8.287 8.287 0 0 0 9 9.601a8.983 8.983 0 0 1 3.361-6.867 8.21 8.21 0 0 0 3 2.48Z" /&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 18a3.75 3.75 0 0 0 .495-7.468 5.99 5.99 0 0 0-1.925 3.547 5.975 5.975 0 0 1-2.133-1.001A3.75 3.75 0 0 0 12 18Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Tip&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Crea &lt;strong&gt;una sola&lt;/strong&gt; &lt;code&gt;ClientSession&lt;/code&gt; y reutilízala para todas tus peticiones. Crear una sesión por petición desperdicia el &lt;em&gt;connection pooling&lt;/em&gt; y degrada el rendimiento.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h3 id="configurando-timeouts"&gt;Configurando Timeouts&lt;/h3&gt;
&lt;p&gt;Por defecto &lt;code&gt;aiohttp&lt;/code&gt; aplica un timeout de &lt;strong&gt;cinco minutos&lt;/strong&gt; a cada operación. Para la mayoría de aplicaciones ese valor es demasiado alto. Podemos ajustarlo con &lt;code&gt;ClientTimeout&lt;/code&gt;, tanto a nivel de sesión (aplica a todas las peticiones) como a nivel de petición individual.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;fetch_status&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;session&lt;/span&gt;: &lt;span style="color:#e06c75"&gt;ClientSession&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;url&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;diez_millis&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;aiohttp&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;ClientTimeout&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;total&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#d19a66"&gt;.01&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# por petición&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;with&lt;/span&gt; &lt;span style="color:#e06c75"&gt;session&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;get&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;url&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;timeout&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#e06c75"&gt;diez_millis&lt;/span&gt;) &lt;span style="color:#c678dd"&gt;as&lt;/span&gt; &lt;span style="color:#e06c75"&gt;result&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;result&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;status&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;main&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;session_timeout&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;aiohttp&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;ClientTimeout&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;total&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;connect&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#d19a66"&gt;.1&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# por sesión&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;with&lt;/span&gt; &lt;span style="color:#e06c75"&gt;aiohttp&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;ClientSession&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;timeout&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#e06c75"&gt;session_timeout&lt;/span&gt;) &lt;span style="color:#c678dd"&gt;as&lt;/span&gt; &lt;span style="color:#e06c75"&gt;session&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;await&lt;/span&gt; &lt;span style="color:#e06c75"&gt;fetch_status&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;session&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;https://example.com&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El parámetro &lt;code&gt;total&lt;/code&gt; limita la duración completa de la operación; &lt;code&gt;connect&lt;/code&gt; limita solo el tiempo de establecer la conexión. El timeout de la petición tiene prioridad sobre el de la sesión.&lt;/p&gt;
&lt;h2 id="la-trampa-del-await-secuencial"&gt;La Trampa del &lt;code&gt;await&lt;/code&gt; Secuencial&lt;/h2&gt;
&lt;p&gt;Antes de lanzar muchas peticiones, hay un error sutil que conviene evitar. Supongamos que queremos ejecutar varias coroutines y recolectar resultados con una &lt;em&gt;list comprehension&lt;/em&gt;:&lt;/p&gt;



&lt;div class="tab" data-tab-group=""&gt;
 &lt;ul class="tab-nav" data-tab-nav&gt;
 
 &lt;li
 class="tab-nav-item active"
 data-tab="secuencial" tabindex="0"&gt;
 ❌ Secuencial
 &lt;/li&gt;
 
 &lt;li
 class="tab-nav-item "
 data-tab="concurrente" tabindex="-1"&gt;
 ✅ Concurrente
 &lt;/li&gt;
 
 &lt;/ul&gt;
 &lt;div class="tab-content" data-tab-content&gt;
 
 &lt;div
 class="tab-content-panel active"
 data-tab-panel="secuencial"&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;main&lt;/span&gt;() &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;None&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;delay_times&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; [&lt;span style="color:#d19a66"&gt;3&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#7f848e"&gt;# await dentro del comprehension → espera cada task antes de crear el siguiente&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [&lt;span style="color:#c678dd"&gt;await&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;create_task&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;delay&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;seconds&lt;/span&gt;)) &lt;span style="color:#c678dd"&gt;for&lt;/span&gt; &lt;span style="color:#e06c75"&gt;seconds&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;in&lt;/span&gt; &lt;span style="color:#e06c75"&gt;delay_times&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Tarda &lt;strong&gt;~9 segundos&lt;/strong&gt;. El &lt;code&gt;await&lt;/code&gt; fuerza a esperar cada task antes de crear el siguiente.&lt;/p&gt;

 &lt;/div&gt;
 
 &lt;div
 class="tab-content-panel "
 data-tab-panel="concurrente"&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;main&lt;/span&gt;() &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;None&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;delay_times&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; [&lt;span style="color:#d19a66"&gt;3&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;, &lt;span style="color:#d19a66"&gt;3&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;tasks&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; [&lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;create_task&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;delay&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;seconds&lt;/span&gt;)) &lt;span style="color:#c678dd"&gt;for&lt;/span&gt; &lt;span style="color:#e06c75"&gt;seconds&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;in&lt;/span&gt; &lt;span style="color:#e06c75"&gt;delay_times&lt;/span&gt;] &lt;span style="color:#7f848e"&gt;# 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; [&lt;span style="color:#c678dd"&gt;await&lt;/span&gt; &lt;span style="color:#e06c75"&gt;task&lt;/span&gt; &lt;span style="color:#c678dd"&gt;for&lt;/span&gt; &lt;span style="color:#e06c75"&gt;task&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;in&lt;/span&gt; &lt;span style="color:#e06c75"&gt;tasks&lt;/span&gt;] &lt;span style="color:#7f848e"&gt;# 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Tarda &lt;strong&gt;~3 segundos&lt;/strong&gt;. Primero se crean todos los tasks, luego se esperan.&lt;/p&gt;

 &lt;/div&gt;
 
 &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;La clave está en separar la &lt;strong&gt;creación&lt;/strong&gt; de los tasks (que los pone a correr en el event loop) de la &lt;strong&gt;espera&lt;/strong&gt; de sus resultados. Si haces &lt;code&gt;await&lt;/code&gt; mientras los creas, los serializas. Esta separación es precisamente lo que las siguientes APIs resuelven por nosotros.&lt;/p&gt;
&lt;h2 id="gather-recolectar-todos-los-resultados"&gt;&lt;code&gt;gather&lt;/code&gt;: Recolectar Todos los Resultados&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;asyncio.gather&lt;/code&gt; recibe una secuencia de awaitables, los ejecuta concurrentemente y, cuando hacemos &lt;code&gt;await&lt;/code&gt; sobre él, espera a que &lt;strong&gt;todos&lt;/strong&gt; terminen y retorna una lista con sus resultados. Si le pasamos coroutines, las envuelve en tasks automáticamente, así que no necesitamos llamar a &lt;code&gt;create_task&lt;/code&gt; manualmente.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;main&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;with&lt;/span&gt; &lt;span style="color:#e06c75"&gt;aiohttp&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;ClientSession&lt;/span&gt;() &lt;span style="color:#c678dd"&gt;as&lt;/span&gt; &lt;span style="color:#e06c75"&gt;session&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;urls&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; [&lt;span style="color:#98c379"&gt;&amp;#39;https://example.com&amp;#39;&lt;/span&gt; &lt;span style="color:#c678dd"&gt;for&lt;/span&gt; &lt;span style="color:#e06c75"&gt;_&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;in&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;range&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1000&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;requests&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; [&lt;span style="color:#e06c75"&gt;fetch_status&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;session&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;url&lt;/span&gt;) &lt;span style="color:#c678dd"&gt;for&lt;/span&gt; &lt;span style="color:#e06c75"&gt;url&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;in&lt;/span&gt; &lt;span style="color:#e06c75"&gt;urls&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;status_codes&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;await&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;gather&lt;/span&gt;(&lt;span style="color:#56b6c2"&gt;*&lt;/span&gt;&lt;span style="color:#e06c75"&gt;requests&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;status_codes&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;&lt;code&gt;gather&lt;/code&gt; ejecuta las 1000 peticiones de forma concurrente y retorna sus códigos de estado.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Una garantía importante: aunque las peticiones terminen en cualquier orden, &lt;strong&gt;los resultados se devuelven en el mismo orden en que pasamos los awaitables&lt;/strong&gt;. Esto hace que &lt;code&gt;gather&lt;/code&gt; sea ideal cuando necesitas correlacionar cada resultado con su entrada.&lt;/p&gt;
&lt;h3 id="manejo-de-excepciones-en-gather"&gt;Manejo de Excepciones en &lt;code&gt;gather&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;El comportamiento ante errores se controla con el parámetro &lt;code&gt;return_exceptions&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;return_exceptions=False&lt;/code&gt;&lt;/strong&gt; (por defecto): si cualquier awaitable lanza una excepción, esa excepción se propaga al hacer &lt;code&gt;await gather&lt;/code&gt;. El resto de coroutines &lt;strong&gt;siguen ejecutándose&lt;/strong&gt;, pero perdemos sus resultados a menos que manejemos la excepción.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;return_exceptions=True&lt;/code&gt;&lt;/strong&gt;: las excepciones se devuelven como parte de la lista de resultados, junto a los valores exitosos. &lt;code&gt;gather&lt;/code&gt; nunca lanza, y nosotros decidimos cómo tratar cada error.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;results&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;await&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;gather&lt;/span&gt;(&lt;span style="color:#56b6c2"&gt;*&lt;/span&gt;&lt;span style="color:#e06c75"&gt;requests&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;return_exceptions&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#e5c07b"&gt;True&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;exitos&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; [&lt;span style="color:#e06c75"&gt;r&lt;/span&gt; &lt;span style="color:#c678dd"&gt;for&lt;/span&gt; &lt;span style="color:#e06c75"&gt;r&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;in&lt;/span&gt; &lt;span style="color:#e06c75"&gt;results&lt;/span&gt; &lt;span style="color:#c678dd"&gt;if&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;not&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;isinstance&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;r&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;Exception&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;errores&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; [&lt;span style="color:#e06c75"&gt;r&lt;/span&gt; &lt;span style="color:#c678dd"&gt;for&lt;/span&gt; &lt;span style="color:#e06c75"&gt;r&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;in&lt;/span&gt; &lt;span style="color:#e06c75"&gt;results&lt;/span&gt; &lt;span style="color:#c678dd"&gt;if&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;isinstance&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;r&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;Exception&lt;/span&gt;)]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;code&gt;gather&lt;/code&gt; tiene dos limitaciones: no es fácil &lt;strong&gt;cancelar&lt;/strong&gt; las peticiones restantes cuando una falla, y debemos esperar a que &lt;strong&gt;todas&lt;/strong&gt; terminen antes de procesar cualquier resultado. Si una petición tarda 20 s y otra 100 ms, nos bloqueamos 20 s antes de poder usar la rápida.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="as_completed-procesar-a-medida-que-terminan"&gt;&lt;code&gt;as_completed&lt;/code&gt;: Procesar a Medida que Terminan&lt;/h2&gt;
&lt;p&gt;Cuando queremos reaccionar a cada resultado &lt;strong&gt;en cuanto está disponible&lt;/strong&gt;, &lt;code&gt;asyncio.as_completed&lt;/code&gt; es la herramienta. Recibe una lista de awaitables y retorna un iterador de futures. Al iterar y hacer &lt;code&gt;await&lt;/code&gt; sobre cada uno, obtenemos los resultados en el orden en que van &lt;strong&gt;completándose&lt;/strong&gt;, no en el que los pasamos.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;main&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;with&lt;/span&gt; &lt;span style="color:#e06c75"&gt;aiohttp&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;ClientSession&lt;/span&gt;() &lt;span style="color:#c678dd"&gt;as&lt;/span&gt; &lt;span style="color:#e06c75"&gt;session&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;fetchers&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;fetch_status&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;session&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;https://example.com&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;delay&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;fetch_status&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;session&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;https://example.com&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;delay&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;fetch_status&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;session&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;https://example.com&amp;#39;&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;delay&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#d19a66"&gt;10&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;for&lt;/span&gt; &lt;span style="color:#e06c75"&gt;finished_task&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;in&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;as_completed&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;fetchers&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#c678dd"&gt;await&lt;/span&gt; &lt;span style="color:#e06c75"&gt;finished_task&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# se imprime apenas cada uno termina&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Las dos primeras peticiones se imprimen alrededor del segundo 1, sin esperar a la de 10 segundos. Esto mejora la &lt;strong&gt;responsividad&lt;/strong&gt; de la aplicación. También nos da mejor control de errores: la excepción de un task se lanza justo cuando hacemos &lt;code&gt;await&lt;/code&gt; sobre él, permitiéndonos manejarla en el momento.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;as_completed&lt;/code&gt; admite un &lt;code&gt;timeout&lt;/code&gt; global. Si se excede, el &lt;code&gt;await&lt;/code&gt; sobre los futures pendientes lanza &lt;code&gt;asyncio.TimeoutError&lt;/code&gt;, que podemos capturar:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;for&lt;/span&gt; &lt;span style="color:#e06c75"&gt;done_task&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;in&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;as_completed&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;fetchers&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;timeout&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#d19a66"&gt;2&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;try&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#c678dd"&gt;await&lt;/span&gt; &lt;span style="color:#e06c75"&gt;done_task&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;except&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;TimeoutError&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;¡Timeout!&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre class="mermaid"&gt;flowchart LR
 subgraph gather[&amp;#34;gather → espera TODO&amp;#34;]
 G1[req 1s] --&amp;gt; GW[⏳ bloquea hasta el más lento]
 G2[req 1s] --&amp;gt; GW
 G3[req 10s] --&amp;gt; GW
 GW --&amp;gt; GR[procesa los 3 resultados]
 end
 subgraph asc[&amp;#34;as_completed → procesa al terminar&amp;#34;]
 A1[req 1s] --&amp;gt; AR1[procesa ~1s]
 A2[req 1s] --&amp;gt; AR2[procesa ~1s]
 A3[req 10s] --&amp;gt; AR3[procesa ~10s]
 end
&lt;/pre&gt;

&lt;p&gt;La desventaja de &lt;code&gt;as_completed&lt;/code&gt; es que no es fácil saber &lt;strong&gt;qué&lt;/strong&gt; tasks ya terminaron y cuáles siguen pendientes: los recibimos uno a uno por el iterador.&lt;/p&gt;
&lt;h2 id="wait-control-fino-sobre-la-espera"&gt;&lt;code&gt;wait&lt;/code&gt;: Control Fino sobre la Espera&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;asyncio.wait&lt;/code&gt; es la opción más flexible. Recibe una colección de tasks y retorna &lt;strong&gt;dos conjuntos&lt;/strong&gt;: &lt;code&gt;done&lt;/code&gt; (los que terminaron, con resultado o excepción) y &lt;code&gt;pending&lt;/code&gt; (los que siguen corriendo). A diferencia de las otras APIs, &lt;code&gt;wait&lt;/code&gt; &lt;strong&gt;no lanza excepciones&lt;/strong&gt; automáticamente ni cancela tasks por timeout; nos da el control y la responsabilidad.&lt;/p&gt;




 
 





 


&lt;div class="notice info"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Info&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Es buena práctica envolver las coroutines en &lt;code&gt;create_task&lt;/code&gt; antes de pasarlas a &lt;code&gt;wait&lt;/code&gt;. En versiones recientes de Python, &lt;code&gt;wait&lt;/code&gt; espera objetos &lt;code&gt;Task&lt;/code&gt;, no coroutines crudas.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Su comportamiento se ajusta con el parámetro &lt;code&gt;return_when&lt;/code&gt;, que acepta tres valores:&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;&lt;code&gt;return_when&lt;/code&gt;&lt;/th&gt;
 &lt;th&gt;&lt;code&gt;wait&lt;/code&gt; retorna cuando…&lt;/th&gt;
 &lt;th&gt;Uso típico&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;ALL_COMPLETED&lt;/code&gt; (def.)&lt;/td&gt;
 &lt;td&gt;todos los tasks terminan&lt;/td&gt;
 &lt;td&gt;equivalente a &lt;code&gt;gather&lt;/code&gt;, pero con &lt;code&gt;done&lt;/code&gt;/&lt;code&gt;pending&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;FIRST_EXCEPTION&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;el primero falla (o todos terminan si no hay errores)&lt;/td&gt;
 &lt;td&gt;cancelar el resto al primer error&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;FIRST_COMPLETED&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;el primero termina (con éxito o error)&lt;/td&gt;
 &lt;td&gt;reaccionar al más rápido y cancelar el resto&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Como &lt;code&gt;wait&lt;/code&gt; nos entrega el conjunto &lt;code&gt;pending&lt;/code&gt;, podemos cancelar explícitamente los tasks que ya no necesitamos:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;main&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;with&lt;/span&gt; &lt;span style="color:#e06c75"&gt;aiohttp&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;ClientSession&lt;/span&gt;() &lt;span style="color:#c678dd"&gt;as&lt;/span&gt; &lt;span style="color:#e06c75"&gt;session&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;fetchers&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;create_task&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;fetch_status&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;session&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;https://example.com&amp;#39;&lt;/span&gt;)),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;create_task&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;fetch_status&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;session&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;https://example.com&amp;#39;&lt;/span&gt;)),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;done&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;pending&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;await&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;wait&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;fetchers&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;return_when&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;=&lt;/span&gt;&lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;FIRST_COMPLETED&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#98c379"&gt;f&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;Terminados: &lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e5c07b"&gt;len&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;done&lt;/span&gt;)&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt; | Pendientes: &lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e5c07b"&gt;len&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;pending&lt;/span&gt;)&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;for&lt;/span&gt; &lt;span style="color:#e06c75"&gt;task&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;in&lt;/span&gt; &lt;span style="color:#e06c75"&gt;done&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;if&lt;/span&gt; &lt;span style="color:#e06c75"&gt;task&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;exception&lt;/span&gt;() &lt;span style="color:#56b6c2"&gt;is&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;None&lt;/span&gt;: &lt;span style="color:#7f848e"&gt;# 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;task&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;result&lt;/span&gt;())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;else&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#98c379"&gt;f&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;Error: &lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e06c75"&gt;task&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;exception&lt;/span&gt;()&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;for&lt;/span&gt; &lt;span style="color:#e06c75"&gt;task&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;in&lt;/span&gt; &lt;span style="color:#e06c75"&gt;pending&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;task&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;cancel&lt;/span&gt;() &lt;span style="color:#7f848e"&gt;# 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;Como los tasks en &lt;code&gt;done&lt;/code&gt; ya terminaron, es seguro consultar &lt;code&gt;exception()&lt;/code&gt; y &lt;code&gt;result()&lt;/code&gt;. Esto evita usar &lt;code&gt;await&lt;/code&gt; con &lt;code&gt;try/except&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Cancelamos manualmente lo que quedó pendiente —algo que &lt;code&gt;gather&lt;/code&gt; no permite hacer con facilidad.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Sobre los &lt;strong&gt;timeouts&lt;/strong&gt; en &lt;code&gt;wait&lt;/code&gt;: si pasas el parámetro &lt;code&gt;timeout&lt;/code&gt; y se agota, &lt;code&gt;wait&lt;/code&gt; simplemente retorna &lt;code&gt;done&lt;/code&gt; y &lt;code&gt;pending&lt;/code&gt; hasta ese momento, &lt;strong&gt;sin lanzar excepción&lt;/strong&gt; y &lt;strong&gt;sin cancelar&lt;/strong&gt; los tasks pendientes. Tú decides qué hacer con ellos.&lt;/p&gt;
&lt;h2 id="cuál-debo-usar"&gt;¿Cuál Debo Usar?&lt;/h2&gt;
&lt;p&gt;Las tres APIs ejecutan awaitables concurrentemente; la elección depende de cómo necesites consumir los resultados.&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart TD
 Start{¿Cómo necesito&amp;lt;br/&amp;gt;los resultados?} --&amp;gt; A[Todos juntos&amp;lt;br/&amp;gt;y ordenados]
 Start --&amp;gt; B[Cada uno apenas&amp;lt;br/&amp;gt;termina]
 Start --&amp;gt; C[Control fino:&amp;lt;br/&amp;gt;done/pending,&amp;lt;br/&amp;gt;cancelar el resto]

 A --&amp;gt; AG[&amp;#34;asyncio.gather&amp;#34;]
 B --&amp;gt; AC[&amp;#34;asyncio.as_completed&amp;#34;]
 C --&amp;gt; AW[&amp;#34;asyncio.wait&amp;#34;]

 style AG fill:#3b82f6,stroke:#1e40af,color:#fff
 style AC fill:#f59e0b,stroke:#b45309,color:#fff
 style AW fill:#10b981,stroke:#065f46,color:#fff
&lt;/pre&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;gather&lt;/code&gt;&lt;/strong&gt; → la opción más simple cuando quieres &lt;strong&gt;todos los resultados, en orden&lt;/strong&gt;, y un único punto donde manejar el éxito o el error.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;as_completed&lt;/code&gt;&lt;/strong&gt; → cuando quieres &lt;strong&gt;procesar cada resultado en cuanto llega&lt;/strong&gt; y mejorar la responsividad.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;wait&lt;/code&gt;&lt;/strong&gt; → cuando necesitas &lt;strong&gt;control fino&lt;/strong&gt;: saber qué terminó y qué sigue pendiente, manejar errores sin excepciones implícitas y cancelar tasks manualmente.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="en-conclusión"&gt;En conclusión&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;aiohttp&lt;/code&gt; es el reemplazo asíncrono de &lt;code&gt;requests&lt;/code&gt;; usa una &lt;code&gt;ClientSession&lt;/code&gt; con &lt;strong&gt;connection pooling&lt;/strong&gt; y reutilízala entre peticiones.&lt;/li&gt;
&lt;li&gt;Tanto la sesión como cada petición son &lt;strong&gt;context managers asíncronos&lt;/strong&gt; (&lt;code&gt;async with&lt;/code&gt;), construidos sobre &lt;code&gt;__aenter__&lt;/code&gt;/&lt;code&gt;__aexit__&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Separa la &lt;strong&gt;creación&lt;/strong&gt; de tasks de su &lt;strong&gt;espera&lt;/strong&gt;: hacer &lt;code&gt;await&lt;/code&gt; mientras los creas los serializa.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gather&lt;/code&gt; espera todo y devuelve resultados &lt;strong&gt;ordenados&lt;/strong&gt;; controla errores con &lt;code&gt;return_exceptions&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;as_completed&lt;/code&gt; entrega resultados &lt;strong&gt;a medida que terminan&lt;/strong&gt;, ideal para responsividad.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;wait&lt;/code&gt; ofrece &lt;strong&gt;control fino&lt;/strong&gt; con los conjuntos &lt;code&gt;done&lt;/code&gt;/&lt;code&gt;pending&lt;/code&gt; y los modos &lt;code&gt;ALL_COMPLETED&lt;/code&gt;, &lt;code&gt;FIRST_EXCEPTION&lt;/code&gt; y &lt;code&gt;FIRST_COMPLETED&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="referencias"&gt;Referencias&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.aiohttp.org/"




 target="_blank"
 


&gt;aiohttp — Documentación Oficial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.python.org/3/library/asyncio-task.html#asyncio.gather"




 target="_blank"
 


&gt;Python &lt;code&gt;asyncio.gather&lt;/code&gt; — Documentación Oficial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.python.org/3/library/asyncio-task.html#asyncio.as_completed"




 target="_blank"
 


&gt;Python &lt;code&gt;asyncio.as_completed&lt;/code&gt; — Documentación Oficial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.python.org/3/library/asyncio-task.html#asyncio.wait"




 target="_blank"
 


&gt;Python &lt;code&gt;asyncio.wait&lt;/code&gt; — Documentación Oficial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://peps.python.org/pep-0492/"




 target="_blank"
 


&gt;PEP 492 — Coroutines with async and await syntax&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Matthew Fowler, &lt;em&gt;Python Concurrency with asyncio&lt;/em&gt; (Manning, 2022)&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>Futures, Awaitables y Errores Comunes en asyncio</title><link>https://blog.dacadev.com/python/asyncio/futures-awaitables-errores-comunes/</link><pubDate>Wed, 13 May 2026 00:00:00 -0500</pubDate><guid>https://blog.dacadev.com/python/asyncio/futures-awaitables-errores-comunes/</guid><dc:creator>Dacadev</dc:creator><category>python</category><description>Entiende qué son los futures y awaitables en asyncio, cómo medir el rendimiento de código asíncrono y los errores más comunes que bloquean el event loop en Python.</description><media:content url="https://blog.dacadev.com/images/python/asyncio/futures-awaitables/banner.png" medium="image" type="image/png"/><content:encoded>
&lt;details class="table-of-content "&gt;
 &lt;summary&gt;
 
 Tabla de Contenido
 
 &lt;/summary&gt;
 &lt;nav id="TableOfContents"&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#futures-un-valor-que-aún-no-existe"&gt;Futures: Un Valor que Aún No Existe&lt;/a&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#futures-en-la-práctica"&gt;Futures en la práctica&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
 &lt;/li&gt;
 &lt;li&gt;&lt;a href="#la-jerarquía-de-los-awaitables"&gt;La Jerarquía de los Awaitables&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#midiendo-el-tiempo-de-ejecución"&gt;Midiendo el Tiempo de Ejecución&lt;/a&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#uso-en-la-práctica"&gt;Uso en la práctica&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
 &lt;/li&gt;
 &lt;li&gt;&lt;a href="#errores-comunes-en-asyncio"&gt;Errores Comunes en &lt;code&gt;asyncio&lt;/code&gt;&lt;/a&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#1-ejecutar-código-cpu-bound-en-coroutines"&gt;1. Ejecutar código CPU-bound en coroutines&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#2-usar-apis-bloqueantes"&gt;2. Usar APIs bloqueantes&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
 &lt;/li&gt;
 &lt;li&gt;&lt;a href="#en-conclusión"&gt;En conclusión&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#referencias"&gt;Referencias&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
&lt;/nav&gt;
&lt;/details&gt;

&lt;p&gt;En los artículos anteriores aprendimos a crear &lt;a href="https://blog.dacadev.com/python/asyncio/coroutines-async-await"



 


&gt;coroutines con async/await&lt;/a&gt; y ejecutar tasks concurrentes. En este artículo vamos a cerrar el modelo mental: entenderemos qué son los &lt;strong&gt;futures&lt;/strong&gt;, cómo se relacionan con tasks y coroutines a través de los &lt;strong&gt;awaitables&lt;/strong&gt;, y veremos cómo medir el rendimiento de nuestro código asíncrono. Para cerrar, hablaremos de los dos errores más comunes al trabajar con &lt;code&gt;asyncio&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="futures-un-valor-que-aún-no-existe"&gt;Futures: Un Valor que Aún No Existe&lt;/h2&gt;
&lt;p&gt;Un &lt;strong&gt;future&lt;/strong&gt; es un objeto de Python que representa un valor que esperamos obtener en algún momento, pero que &lt;strong&gt;todavía no tenemos&lt;/strong&gt;. Cuando se crea, un future está en estado &lt;em&gt;incompleto&lt;/em&gt;. Una vez que el valor llega, se establece con &lt;code&gt;set_result&lt;/code&gt; y el future pasa a estar &lt;em&gt;completado&lt;/em&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt; &lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Future&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;my_future&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Future&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#98c379"&gt;f&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;¿Está completo? &lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e06c75"&gt;my_future&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;done&lt;/span&gt;()&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# False&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;my_future&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;set_result&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;42&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#98c379"&gt;f&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;¿Está completo? &lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e06c75"&gt;my_future&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;done&lt;/span&gt;()&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#98c379"&gt;f&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;Resultado: &lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e06c75"&gt;my_future&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;result&lt;/span&gt;()&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# 42&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre class="mermaid"&gt;stateDiagram-v2
 [*] --&amp;gt; Incompleto: Future()
 Incompleto --&amp;gt; Completado: set_result(valor)
 Completado --&amp;gt; [*]: result() → valor

 note right of Incompleto
 done() → False
 result() → InvalidStateError
 end note

 note right of Completado
 done() → True
 result() → valor
 end note
&lt;/pre&gt;

&lt;h3 id="futures-en-la-práctica"&gt;Futures en la práctica&lt;/h3&gt;
&lt;p&gt;En la mayoría de los casos no crearás futures directamente — &lt;code&gt;asyncio&lt;/code&gt; los gestiona internamente. Pero entender su mecánica es clave para comprender cómo funciona todo por dentro. Veamos un ejemplo donde un task establece el valor de un future después de un segundo:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt; &lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Future&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;hacer_peticion&lt;/span&gt;() &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Future&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;future&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Future&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;create_task&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;establecer_valor&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;future&lt;/span&gt;)) &lt;span style="color:#7f848e"&gt;# 1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;future&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;establecer_valor&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;future&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;None&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;await&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;sleep&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;future&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;set_result&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;42&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;main&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;future&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;hacer_peticion&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#98c379"&gt;f&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;¿Está completo? &lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e06c75"&gt;future&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;done&lt;/span&gt;()&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# False&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;valor&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;await&lt;/span&gt; &lt;span style="color:#e06c75"&gt;future&lt;/span&gt; &lt;span style="color:#7f848e"&gt;# 3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#98c379"&gt;f&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;¿Está completo? &lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e06c75"&gt;future&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;done&lt;/span&gt;()&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;valor&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# 42&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;run&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;main&lt;/span&gt;())
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;Crea un task que configurará el valor del future.&lt;/li&gt;
&lt;li&gt;Espera 1 segundo antes de establecer el resultado.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;await&lt;/code&gt; pausa &lt;code&gt;main()&lt;/code&gt; hasta que el future reciba su valor.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="mermaid"&gt;sequenceDiagram
 participant M as main()
 participant F as Future
 participant T as task: establecer_valor()

 M-&amp;gt;&amp;gt;F: hacer_peticion() → Future incompleto
 M-&amp;gt;&amp;gt;T: create_task(establecer_valor(future))
 M-&amp;gt;&amp;gt;F: await future
 Note over M: ⏸ PAUSE main()
 T-&amp;gt;&amp;gt;T: await asyncio.sleep(1)
 Note over T: ⏳ 1 segundo...
 T-&amp;gt;&amp;gt;F: set_result(42)
 Note over F: ✅ Completado
 F--&amp;gt;&amp;gt;M: ▶ RESUME main()
 Note over M: valor = 42
&lt;/pre&gt;

&lt;h2 id="la-jerarquía-de-los-awaitables"&gt;La Jerarquía de los Awaitables&lt;/h2&gt;
&lt;p&gt;Tanto las coroutines como los tasks pueden usarse con &lt;code&gt;await&lt;/code&gt;. ¿Qué tienen en común? Ambos son &lt;strong&gt;awaitables&lt;/strong&gt; — objetos que implementan el método &lt;code&gt;__await__&lt;/code&gt;, que es lo que Python necesita para poder usar la palabra clave &lt;code&gt;await&lt;/code&gt; sobre ellos.&lt;/p&gt;
&lt;p&gt;La relación entre estos conceptos forma una jerarquía clara:&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart TD
 A[&amp;#34;Awaitable\n(__await__)&amp;#34;] --&amp;gt; B[&amp;#34;Coroutine&amp;#34;]
 A --&amp;gt; C[&amp;#34;Future&amp;#34;]
 C --&amp;gt; D[&amp;#34;Task&amp;#34;]

 style A fill:#8b5cf6,stroke:#5b21b6,color:#fff
 style B fill:#3b82f6,stroke:#1e40af,color:#fff
 style C fill:#f59e0b,stroke:#b45309,color:#fff
 style D fill:#10b981,stroke:#065f46,color:#fff
&lt;/pre&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Awaitable&lt;/strong&gt; es la clase base que define el protocolo &lt;code&gt;__await__&lt;/code&gt;. Todo lo que se pueda usar con &lt;code&gt;await&lt;/code&gt; es un awaitable.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Coroutine&lt;/strong&gt; es una función definida con &lt;code&gt;async def&lt;/code&gt;. Hereda de &lt;code&gt;Awaitable&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Future&lt;/strong&gt; representa un valor pendiente. También hereda de &lt;code&gt;Awaitable&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Task&lt;/strong&gt; hereda de &lt;code&gt;Future&lt;/code&gt;. Es la combinación de un future y una coroutine: encapsula una coroutine y la ejecuta en el event loop, mientras que el future subyacente almacena el resultado cuando la coroutine termina.&lt;/li&gt;
&lt;/ul&gt;




 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Un &lt;strong&gt;Future&lt;/strong&gt; es &lt;em&gt;qué&lt;/em&gt; esperamos obtener. Un &lt;strong&gt;Task&lt;/strong&gt; es &lt;em&gt;cómo&lt;/em&gt; lo obtenemos (ejecutando una coroutine). Y &lt;strong&gt;Awaitable&lt;/strong&gt; es el contrato que ambos cumplen para que &lt;code&gt;await&lt;/code&gt; funcione.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="midiendo-el-tiempo-de-ejecución"&gt;Midiendo el Tiempo de Ejecución&lt;/h2&gt;
&lt;p&gt;Cuando trabajamos con código asíncrono, medir cuánto tarda cada operación es esencial para verificar que la concurrencia realmente funciona. La mejor forma de hacerlo es con un &lt;strong&gt;decorador&lt;/strong&gt; que registre el tiempo de inicio y fin de cada coroutine:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;functools&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;time&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#e06c75"&gt;typing&lt;/span&gt; &lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Callable&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;Any&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;async_timed&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;wrapper&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;func&lt;/span&gt;: &lt;span style="color:#e06c75"&gt;Callable&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Callable&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#61afef"&gt;@functools.wraps&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;func&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;wrapped&lt;/span&gt;(&lt;span style="color:#56b6c2"&gt;*&lt;/span&gt;&lt;span style="color:#e06c75"&gt;args&lt;/span&gt;, &lt;span style="color:#56b6c2"&gt;**&lt;/span&gt;&lt;span style="color:#e06c75"&gt;kwargs&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e06c75"&gt;Any&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#98c379"&gt;f&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;starting &lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e06c75"&gt;func&lt;/span&gt;&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt; with args &lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e06c75"&gt;args&lt;/span&gt;&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt; &lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e06c75"&gt;kwargs&lt;/span&gt;&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;start&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;time&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;time&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;try&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#c678dd"&gt;await&lt;/span&gt; &lt;span style="color:#e06c75"&gt;func&lt;/span&gt;(&lt;span style="color:#56b6c2"&gt;*&lt;/span&gt;&lt;span style="color:#e06c75"&gt;args&lt;/span&gt;, &lt;span style="color:#56b6c2"&gt;**&lt;/span&gt;&lt;span style="color:#e06c75"&gt;kwargs&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;finally&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;end&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;time&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;time&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;total&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;end&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;-&lt;/span&gt; &lt;span style="color:#e06c75"&gt;start&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#98c379"&gt;f&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;finished &lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e06c75"&gt;func&lt;/span&gt;&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt; in &lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e06c75"&gt;total&lt;/span&gt;&lt;span style="color:#98c379"&gt;:&lt;/span&gt;&lt;span style="color:#98c379"&gt;.4f&lt;/span&gt;&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt; second(s)&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;wrapped&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;wrapper&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="uso-en-la-práctica"&gt;Uso en la práctica&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#61afef"&gt;@async_timed&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;delay&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;delay_seconds&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#98c379"&gt;f&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;sleeping for &lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e06c75"&gt;delay_seconds&lt;/span&gt;&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt; second(s)&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;await&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;sleep&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;delay_seconds&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#98c379"&gt;f&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;finished sleeping for &lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e06c75"&gt;delay_seconds&lt;/span&gt;&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt; second(s)&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;delay_seconds&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#61afef"&gt;@async_timed&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;main&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;task_one&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;create_task&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;delay&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;2&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;task_two&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;create_task&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;delay&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;3&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;await&lt;/span&gt; &lt;span style="color:#e06c75"&gt;task_one&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;await&lt;/span&gt; &lt;span style="color:#e06c75"&gt;task_two&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;run&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;main&lt;/span&gt;())
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;starting &amp;lt;function main ...&amp;gt; with args () {}
starting &amp;lt;function delay ...&amp;gt; with args (2,) {}
starting &amp;lt;function delay ...&amp;gt; with args (3,) {}
finished &amp;lt;function delay ...&amp;gt; in 2.0032 second(s)
finished &amp;lt;function delay ...&amp;gt; in 3.0003 second(s)
finished &amp;lt;function main ...&amp;gt; in 3.0004 second(s)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;El output confirma lo que esperamos: ambos tasks corren concurrentemente. &lt;code&gt;delay(2)&lt;/code&gt; termina a los ~2 segundos, &lt;code&gt;delay(3)&lt;/code&gt; a los ~3, y &lt;code&gt;main()&lt;/code&gt; tarda ~3 segundos en total (no 5).&lt;/p&gt;
&lt;pre class="mermaid"&gt;gantt
 title Ejecución concurrente verificada con @async_timed
 dateFormat X
 axisFormat %s

 section delay(2)
 sleep(2) :a1, 0, 2

 section delay(3)
 sleep(3) :b1, 0, 3

 section main()
 Tiempo total :c1, 0, 3
&lt;/pre&gt;

&lt;h2 id="errores-comunes-en-asyncio"&gt;Errores Comunes en &lt;code&gt;asyncio&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Hay dos trampas frecuentes que pueden arruinar el rendimiento de una aplicación async. Ambas tienen la misma causa: &lt;strong&gt;bloquear el event loop&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id="1-ejecutar-código-cpu-bound-en-coroutines"&gt;1. Ejecutar código CPU-bound en coroutines&lt;/h3&gt;
&lt;p&gt;Cuando tenemos funciones computacionalmente costosas (cálculos matemáticos, procesamiento de datos grandes), puede parecer buena idea envolverlas en tasks para ejecutarlas concurrentemente. Pero recuerda: &lt;code&gt;asyncio&lt;/code&gt; usa &lt;strong&gt;un solo hilo&lt;/strong&gt;. El GIL garantiza que solo una instrucción de bytecode se ejecute a la vez, así que el código CPU-bound bloqueará el event loop sin importar cuántos tasks crees.&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart LR
 A[&amp;#34;Código CPU-bound\nen una coroutine&amp;#34;] --&amp;gt;|&amp;#34;Bloquea el\nevent loop 🛑&amp;#34;| B[&amp;#34;Otras tareas\nno pueden ejecutarse&amp;#34;]
 C[&amp;#34;Solución&amp;#34;] --&amp;gt; D[&amp;#34;multiprocessing\no run_in_executor()&amp;#34;]

 style A fill:#ef4444,stroke:#991b1b,color:#fff
 style B fill:#ef4444,stroke:#991b1b,color:#fff
 style D fill:#10b981,stroke:#065f46,color:#fff
&lt;/pre&gt;

&lt;h3 id="2-usar-apis-bloqueantes"&gt;2. Usar APIs bloqueantes&lt;/h3&gt;
&lt;p&gt;El mismo problema ocurre al usar librerías de I/O que no son asíncronas. Librerías como &lt;code&gt;requests&lt;/code&gt; o funciones como &lt;code&gt;time.sleep&lt;/code&gt; bloquean el hilo principal. Cuando las llamas dentro de una coroutine, &lt;strong&gt;bloqueas el event loop completo&lt;/strong&gt; y ninguna otra coroutine puede ejecutarse.&lt;/p&gt;



&lt;div class="tab" data-tab-group=""&gt;
 &lt;ul class="tab-nav" data-tab-nav&gt;
 
 &lt;li
 class="tab-nav-item active"
 data-tab="bloqueante" tabindex="0"&gt;
 ❌ Bloqueante
 &lt;/li&gt;
 
 &lt;li
 class="tab-nav-item "
 data-tab="no-bloqueante" tabindex="-1"&gt;
 ✅ No bloqueante
 &lt;/li&gt;
 
 &lt;/ul&gt;
 &lt;div class="tab-content" data-tab-content&gt;
 
 &lt;div
 class="tab-content-panel active"
 data-tab-panel="bloqueante"&gt;
 &lt;h4 id="no-uses-estas-funciones-dentro-de-coroutines"&gt;No uses estas funciones dentro de coroutines&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;requests.get()&lt;/code&gt; → bloquea el event loop&lt;/li&gt;
&lt;li&gt;&lt;code&gt;time.sleep()&lt;/code&gt; → bloquea el event loop&lt;/li&gt;
&lt;li&gt;Cualquier función de I/O síncrona&lt;/li&gt;
&lt;/ul&gt;

 &lt;/div&gt;
 
 &lt;div
 class="tab-content-panel "
 data-tab-panel="no-bloqueante"&gt;
 &lt;h4 id="usa-las-alternativas-asíncronas"&gt;Usa las alternativas asíncronas&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.aiohttp.org/"




 target="_blank"
 


&gt;&lt;code&gt;aiohttp&lt;/code&gt;&lt;/a&gt; → reemplazo async de &lt;code&gt;requests&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;asyncio.sleep()&lt;/code&gt; → cede control al event loop&lt;/li&gt;
&lt;li&gt;&lt;a href="https://magicstack.github.io/asyncpg/"




 target="_blank"
 


&gt;&lt;code&gt;asyncpg&lt;/code&gt;&lt;/a&gt; → cliente async de PostgreSQL&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Tinche/aiofiles"




 target="_blank"
 


&gt;&lt;code&gt;aiofiles&lt;/code&gt;&lt;/a&gt; → lectura/escritura async de archivos&lt;/li&gt;
&lt;/ul&gt;

 &lt;/div&gt;
 
 &lt;/div&gt;
&lt;/div&gt;





 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;strong&gt;Regla general:&lt;/strong&gt; cualquier función que realice I/O y no sea una coroutine, o que ejecute operaciones CPU costosas, debe considerarse bloqueante. Para CPU-bound, usa &lt;a href="https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.loop.run_in_executor"




 target="_blank"
 


&gt;&lt;code&gt;loop.run_in_executor()&lt;/code&gt;&lt;/a&gt; con un &lt;code&gt;ProcessPoolExecutor&lt;/code&gt;.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="en-conclusión"&gt;En conclusión&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Un &lt;strong&gt;Future&lt;/strong&gt; representa un valor que aún no existe — se completa con &lt;code&gt;set_result&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Un &lt;strong&gt;Task&lt;/strong&gt; es un future + una coroutine: ejecuta la coroutine y almacena su resultado en el future subyacente.&lt;/li&gt;
&lt;li&gt;Todo lo que se pueda usar con &lt;code&gt;await&lt;/code&gt; es un &lt;strong&gt;Awaitable&lt;/strong&gt; — el contrato que unifica coroutines, futures y tasks.&lt;/li&gt;
&lt;li&gt;El decorador &lt;code&gt;@async_timed&lt;/code&gt; permite verificar que la concurrencia funciona midiendo tiempos reales.&lt;/li&gt;
&lt;li&gt;Los dos errores más comunes son ejecutar &lt;strong&gt;código CPU-bound&lt;/strong&gt; y usar &lt;strong&gt;APIs bloqueantes&lt;/strong&gt; dentro de coroutines — ambos bloquean el event loop.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="referencias"&gt;Referencias&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.python.org/3/library/asyncio-future.html"




 target="_blank"
 


&gt;Python &lt;code&gt;asyncio.Future&lt;/code&gt; — Documentación Oficial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.python.org/3/library/asyncio-task.html#asyncio.Task"




 target="_blank"
 


&gt;Python &lt;code&gt;asyncio.Task&lt;/code&gt; — Documentación Oficial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.python.org/3/reference/datamodel.html#awaitable-objects"




 target="_blank"
 


&gt;Python Data Model — Awaitables&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://realpython.com/async-io-python/"




 target="_blank"
 


&gt;Real Python — Async IO in Python: A Complete Walkthrough&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://peps.python.org/pep-3156/"




 target="_blank"
 


&gt;PEP 3156 — Asynchronous IO Support Rebooted&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>Coroutines y async/await: Tu Primer Código Asíncrono en Python</title><link>https://blog.dacadev.com/python/asyncio/coroutines-async-await/</link><pubDate>Tue, 12 May 2026 00:00:00 -0500</pubDate><guid>https://blog.dacadev.com/python/asyncio/coroutines-async-await/</guid><dc:creator>Dacadev</dc:creator><category>python</category><description>Aprende a crear coroutines con async def, pausar la ejecución con await, usar asyncio.run y evitar la trampa del await secuencial en Python.</description><media:content url="https://blog.dacadev.com/images/python/asyncio/coroutines-async-await/banner.png" medium="image" type="image/png"/><content:encoded>
&lt;details class="table-of-content "&gt;
 &lt;summary&gt;
 
 Tabla de Contenido
 
 &lt;/summary&gt;
 &lt;nav id="TableOfContents"&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#qué-es-una-coroutine"&gt;¿Qué es una Coroutine?&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#creando-coroutines"&gt;Creando Coroutines&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#ejecutando-coroutines-con-asynciorun"&gt;Ejecutando Coroutines con &lt;code&gt;asyncio.run&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#pausando-la-ejecución-con-await"&gt;Pausando la Ejecución con &lt;code&gt;await&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#simulando-operaciones-largas-con-asynciosleep"&gt;Simulando Operaciones Largas con &lt;code&gt;asyncio.sleep&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#la-trampa-del-await-secuencial"&gt;La Trampa del &lt;code&gt;await&lt;/code&gt; Secuencial&lt;/a&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#el-problema-visualizado"&gt;El problema visualizado&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#cómo-logramos-concurrencia-real"&gt;¿Cómo logramos concurrencia real?&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
 &lt;/li&gt;
 &lt;li&gt;&lt;a href="#en-conclusión"&gt;En conclusión&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#referencias"&gt;Referencias&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
&lt;/nav&gt;
&lt;/details&gt;

&lt;p&gt;En los artículos anteriores construimos la base teórica: &lt;a href="https://blog.dacadev.com/python/asyncio/fundamentos-asyncio"



 


&gt;concurrencia vs paralelismo&lt;/a&gt;, &lt;a href="https://blog.dacadev.com/python/asyncio/procesos-hilos-event-loop"



 


&gt;procesos, hilos, el GIL y el event loop&lt;/a&gt;. Ahora es momento de escribir código. En este artículo vamos a aprender a crear &lt;strong&gt;coroutines&lt;/strong&gt;, usar las palabras clave &lt;code&gt;async&lt;/code&gt; y &lt;code&gt;await&lt;/code&gt;, y entender exactamente qué pasa cuando pausamos y reanudamos la ejecución.&lt;/p&gt;
&lt;h2 id="qué-es-una-coroutine"&gt;¿Qué es una Coroutine?&lt;/h2&gt;
&lt;p&gt;Una coroutine es como una función normal de Python, pero con un superpoder: &lt;strong&gt;puede pausar su ejecución&lt;/strong&gt; cuando encuentra una operación que podría tardar (una petición de red, una lectura de disco, una espera). Mientras la coroutine está pausada, el event loop puede ejecutar otras tareas. Cuando la operación termina, la coroutine se &amp;ldquo;despierta&amp;rdquo; y continúa desde donde se detuvo.&lt;/p&gt;
&lt;p&gt;Esta capacidad de pausar y reanudar es lo que le da concurrencia a nuestra aplicación.&lt;/p&gt;
&lt;p&gt;Para trabajar con coroutines necesitamos dos palabras clave:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;async def&lt;/code&gt;&lt;/strong&gt; → define una coroutine.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;await&lt;/code&gt;&lt;/strong&gt; → pausa la coroutine hasta que la operación esperada termine.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="creando-coroutines"&gt;Creando Coroutines&lt;/h2&gt;
&lt;p&gt;Crear una coroutine es casi idéntico a crear una función normal. La única diferencia es usar &lt;code&gt;async def&lt;/code&gt; en lugar de &lt;code&gt;def&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;mi_coroutine&lt;/span&gt;() &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;None&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;¡Hola mundo!&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



 
 





 


&lt;div class="notice info"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Info&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;strong&gt;Llamar a una coroutine no la ejecuta.&lt;/strong&gt; Solo produce un objeto coroutine. Para ejecutarla, necesitas un event loop.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;# ❌ Esto NO ejecuta la coroutine&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;mi_coroutine&lt;/span&gt;() &lt;span style="color:#7f848e"&gt;# Retorna un objeto coroutine, no imprime nada&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;# ✅ Esto SÍ la ejecuta&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;run&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;mi_coroutine&lt;/span&gt;()) &lt;span style="color:#7f848e"&gt;# Imprime: ¡Hola mundo!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="ejecutando-coroutines-con-asynciorun"&gt;Ejecutando Coroutines con &lt;code&gt;asyncio.run&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;asyncio.run&lt;/code&gt; es el &lt;strong&gt;punto de entrada principal&lt;/strong&gt; de cualquier aplicación asyncio. Veamos un ejemplo concreto:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;sumar_uno&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;numero&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;numero&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;+&lt;/span&gt; &lt;span style="color:#d19a66"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;resultado&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;run&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;sumar_uno&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;resultado&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;asyncio.run&lt;/code&gt; hace varias cosas por nosotros:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Crea&lt;/strong&gt; un event loop nuevo.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ejecuta&lt;/strong&gt; la coroutine que le pasamos hasta que se completa.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Retorna&lt;/strong&gt; el resultado de la coroutine.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Limpia&lt;/strong&gt; cualquier tarea pendiente y cierra el event loop.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="mermaid"&gt;flowchart LR
 A[&amp;#34;asyncio.run(coroutine)&amp;#34;] --&amp;gt; B[&amp;#34;Crea el\nEvent Loop&amp;#34;]
 B --&amp;gt; C[&amp;#34;Ejecuta la\ncoroutine&amp;#34;]
 C --&amp;gt; D[&amp;#34;Retorna\nel resultado&amp;#34;]
 D --&amp;gt; E[&amp;#34;Cierra el\nEvent Loop&amp;#34;]

 style A fill:#3b82f6,stroke:#1e40af,color:#fff
 style C fill:#10b981,stroke:#065f46,color:#fff
 style E fill:#64748b,stroke:#334155,color:#fff
&lt;/pre&gt;





 
 





 


&lt;div class="notice info"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Info&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;code&gt;asyncio.run&lt;/code&gt; está diseñado para ejecutarse &lt;strong&gt;una sola vez&lt;/strong&gt; como entrada principal de tu aplicación. Esa única coroutine debería encargarse de lanzar todas las demás tareas.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="pausando-la-ejecución-con-await"&gt;Pausando la Ejecución con &lt;code&gt;await&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;El verdadero poder de asyncio está en &lt;code&gt;await&lt;/code&gt;. Esta palabra clave hace dos cosas:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Ejecuta&lt;/strong&gt; la coroutine que le sigue (a diferencia de llamarla directamente, que solo crea el objeto).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pausa&lt;/strong&gt; la coroutine contenedora hasta que la coroutine esperada retorne un resultado.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Cuando la coroutine esperada termina, la coroutine contenedora se &amp;ldquo;despierta&amp;rdquo; y puede usar el resultado.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;obtener_saludo&lt;/span&gt;() &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;¡Hola desde una coroutine!&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;main&lt;/span&gt;() &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;None&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;saludo&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;await&lt;/span&gt; &lt;span style="color:#e06c75"&gt;obtener_saludo&lt;/span&gt;() &lt;span style="color:#7f848e"&gt;# Pausa main() hasta obtener el resultado&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;saludo&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;run&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;main&lt;/span&gt;())
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="simulando-operaciones-largas-con-asynciosleep"&gt;Simulando Operaciones Largas con &lt;code&gt;asyncio.sleep&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Para simular una operación de I/O de larga duración (como una petición HTTP o una consulta a base de datos), podemos usar &lt;code&gt;asyncio.sleep&lt;/code&gt;. Esta función pausa la coroutine por el número de segundos indicado, cediendo el control al event loop.&lt;/p&gt;
&lt;p&gt;Veamos un ejemplo más completo con una función auxiliar &lt;code&gt;delay&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;delay&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;seconds&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#98c379"&gt;f&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;Esperando &lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e06c75"&gt;seconds&lt;/span&gt;&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt; segundo(s)...&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;await&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;sleep&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;seconds&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#98c379"&gt;f&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;¡Espera de &lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e06c75"&gt;seconds&lt;/span&gt;&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt; segundo(s) completada!&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#98c379"&gt;f&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;Esperé &lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e06c75"&gt;seconds&lt;/span&gt;&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt; segundo(s)&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="la-trampa-del-await-secuencial"&gt;La Trampa del &lt;code&gt;await&lt;/code&gt; Secuencial&lt;/h2&gt;
&lt;p&gt;Ahora veamos un error muy común al empezar con asyncio. Considera este código:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;sumar_uno&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;numero&lt;/span&gt;: &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;) &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;int&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#e06c75"&gt;numero&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;+&lt;/span&gt; &lt;span style="color:#d19a66"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;mensaje_hola_mundo&lt;/span&gt;() &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;str&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;await&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;sleep&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;return&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;¡Hola Mundo!&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;main&lt;/span&gt;() &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;None&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;mensaje&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;await&lt;/span&gt; &lt;span style="color:#e06c75"&gt;mensaje_hola_mundo&lt;/span&gt;() &lt;span style="color:#7f848e"&gt;# Pausa 1 segundo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;uno_mas_uno&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;await&lt;/span&gt; &lt;span style="color:#e06c75"&gt;sumar_uno&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# Ejecuta después de la pausa&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;uno_mas_uno&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;mensaje&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;run&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;main&lt;/span&gt;())
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Cuando ejecutamos este código, &lt;strong&gt;pasa 1 segundo&lt;/strong&gt; antes de que se impriman ambos resultados. Pero &lt;code&gt;sumar_uno(1)&lt;/code&gt; es instantánea — ¿por qué espera?&lt;/p&gt;




 
 





 


&lt;div class="notice warning"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Warning&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;await&lt;/code&gt; pausa toda la coroutine contenedora.&lt;/strong&gt; No se ejecuta ningún otro código dentro de &lt;code&gt;main()&lt;/code&gt; hasta que la expresión &lt;code&gt;await&lt;/code&gt; retorne un valor. Como &lt;code&gt;mensaje_hola_mundo()&lt;/code&gt; tarda 1 segundo, &lt;code&gt;main()&lt;/code&gt; queda pausada ese segundo completo antes de siquiera llegar a &lt;code&gt;sumar_uno(1)&lt;/code&gt;.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;El siguiente diagrama muestra exactamente qué pasa en cada momento:&lt;/p&gt;
&lt;pre class="mermaid"&gt;sequenceDiagram
 participant EL as Event Loop
 participant M as main()
 participant HW as mensaje_hola_mundo()
 participant AO as sumar_uno(1)

 EL-&amp;gt;&amp;gt;M: ▶ RUN main()
 Note over M: await mensaje_hola_mundo()
 M-&amp;gt;&amp;gt;HW: ▶ RUN mensaje_hola_mundo()
 HW-&amp;gt;&amp;gt;HW: await sleep(1)
 Note over M: ⏸ PAUSE main()
 Note over HW: ⏸ PAUSE mensaje_hola_mundo()
 Note over EL: ⏳ Pasa 1 segundo...
 EL-&amp;gt;&amp;gt;HW: ▶ RESUME mensaje_hola_mundo()
 Note over HW: return &amp;#39;¡Hola Mundo!&amp;#39;
 HW--&amp;gt;&amp;gt;M: ▶ RESUME main()
 Note over M: mensaje = &amp;#39;¡Hola Mundo!&amp;#39;
 Note over M: await sumar_uno(1)
 M-&amp;gt;&amp;gt;AO: ▶ RUN sumar_uno(1)
 Note over AO: return 1 + 1
 AO--&amp;gt;&amp;gt;M: ▶ RESUME main()
 Note over M: uno_mas_uno = 2
 Note over M: print() resultados
&lt;/pre&gt;

&lt;h3 id="el-problema-visualizado"&gt;El problema visualizado&lt;/h3&gt;
&lt;p&gt;El flujo de ejecución es completamente &lt;strong&gt;secuencial&lt;/strong&gt;, a pesar de usar &lt;code&gt;async/await&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="mermaid"&gt;gantt
 title Ejecución secuencial — Sin concurrencia real
 dateFormat X
 axisFormat %s

 section main()
 await mensaje_hola_mundo() :a1, 0, 10
 await sumar_uno(1) :a2, 10, 11
 print() resultados :a3, 11, 12
&lt;/pre&gt;

&lt;p&gt;Lo que &lt;em&gt;queremos&lt;/em&gt; es que &lt;code&gt;sumar_uno(1)&lt;/code&gt; se ejecute &lt;strong&gt;mientras&lt;/strong&gt; &lt;code&gt;mensaje_hola_mundo()&lt;/code&gt; espera su segundo de delay. Pero con &lt;code&gt;await&lt;/code&gt; secuencial eso no es posible — cada &lt;code&gt;await&lt;/code&gt; bloquea la coroutine hasta completarse.&lt;/p&gt;
&lt;h3 id="cómo-logramos-concurrencia-real"&gt;¿Cómo logramos concurrencia real?&lt;/h3&gt;
&lt;p&gt;Para ejecutar múltiples coroutines de forma concurrente necesitamos herramientas como &lt;code&gt;asyncio.gather&lt;/code&gt; o &lt;code&gt;asyncio.create_task&lt;/code&gt;. Un adelanto rápido:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;main&lt;/span&gt;() &lt;span style="color:#56b6c2"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;None&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#7f848e"&gt;# ✅ Ambas coroutines corren concurrentemente&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;mensaje&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;uno_mas_uno&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#c678dd"&gt;await&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;gather&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;mensaje_hola_mundo&lt;/span&gt;(),
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;sumar_uno&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;uno_mas_uno&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;mensaje&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Con &lt;code&gt;gather&lt;/code&gt;, el event loop puede ejecutar &lt;code&gt;sumar_uno(1)&lt;/code&gt; mientras &lt;code&gt;mensaje_hola_mundo()&lt;/code&gt; está pausada esperando su &lt;code&gt;sleep&lt;/code&gt;. El tiempo total se mantiene en ~1 segundo en lugar de sumar ambos tiempos.&lt;/p&gt;
&lt;pre class="mermaid"&gt;gantt
 title Ejecución concurrente — Con asyncio.gather
 dateFormat X
 axisFormat %s

 section mensaje_hola_mundo()
 await sleep(1) :a1, 0, 10

 section sumar_uno(1)
 return 1 + 1 :a2, 0, 1

 section main()
 print() resultados :a3, 10, 11
&lt;/pre&gt;

&lt;h2 id="en-conclusión"&gt;En conclusión&lt;/h2&gt;
&lt;pre class="mermaid"&gt;flowchart TD
 A[&amp;#34;async def&amp;#34;] --&amp;gt;|&amp;#34;Define&amp;#34;| B[&amp;#34;Coroutine&amp;#34;]
 B --&amp;gt;|&amp;#34;Se ejecuta con&amp;#34;| C[&amp;#34;asyncio.run()&amp;#34;]
 B --&amp;gt;|&amp;#34;Se pausa con&amp;#34;| D[&amp;#34;await&amp;#34;]
 D --&amp;gt;|&amp;#34;Cede control al&amp;#34;| E[&amp;#34;Event Loop&amp;#34;]
 E --&amp;gt;|&amp;#34;Cuando I/O completa&amp;#34;| F[&amp;#34;Reanuda la coroutine&amp;#34;]
 C --&amp;gt;|&amp;#34;Crea y gestiona&amp;#34;| E

 style A fill:#8b5cf6,stroke:#5b21b6,color:#fff
 style B fill:#3b82f6,stroke:#1e40af,color:#fff
 style D fill:#f59e0b,stroke:#b45309,color:#fff
 style E fill:#10b981,stroke:#065f46,color:#fff
&lt;/pre&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;async def&lt;/code&gt;&lt;/strong&gt; define una coroutine — una función que puede pausarse.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;await&lt;/code&gt;&lt;/strong&gt; pausa la coroutine actual hasta que la operación esperada termine.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;asyncio.run&lt;/code&gt;&lt;/strong&gt; crea el event loop y ejecuta la coroutine principal.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;asyncio.sleep&lt;/code&gt;&lt;/strong&gt; simula operaciones de I/O de larga duración.&lt;/li&gt;
&lt;li&gt;Usar &lt;code&gt;await&lt;/code&gt; de forma secuencial &lt;strong&gt;no da concurrencia&lt;/strong&gt; — para eso necesitamos &lt;code&gt;asyncio.gather&lt;/code&gt; o &lt;code&gt;asyncio.create_task&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="referencias"&gt;Referencias&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.python.org/3/library/asyncio-task.html"




 target="_blank"
 


&gt;Python &lt;code&gt;asyncio&lt;/code&gt; — Documentación Oficial: Coroutines and Tasks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://peps.python.org/pep-0492/"




 target="_blank"
 


&gt;PEP 492 — Coroutines with async and await syntax&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://realpython.com/async-io-python/"




 target="_blank"
 


&gt;Real Python — Async IO in Python: A Complete Walkthrough&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>asyncio: Cómo Funcionan los Procesos, Hilos y el Event Loop</title><link>https://blog.dacadev.com/python/asyncio/procesos-hilos-event-loop/</link><pubDate>Mon, 11 May 2026 00:00:00 -0500</pubDate><guid>https://blog.dacadev.com/python/asyncio/procesos-hilos-event-loop/</guid><dc:creator>Dacadev</dc:creator><category>python</category><description>Entiende qué son los procesos e hilos en Python, cómo el GIL afecta la concurrencia, y cómo asyncio logra concurrencia con un solo hilo gracias al event loop.</description><media:content url="https://blog.dacadev.com/images/python/asyncio/processes-threads/banner.png" medium="image" type="image/png"/><content:encoded>
&lt;details class="table-of-content "&gt;
 &lt;summary&gt;
 
 Tabla de Contenido
 
 &lt;/summary&gt;
 &lt;nav id="TableOfContents"&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#procesos-e-hilos"&gt;Procesos e Hilos&lt;/a&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#qué-es-un-proceso"&gt;¿Qué es un proceso?&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#qué-es-un-hilo-thread"&gt;¿Qué es un hilo (thread)?&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#verificándolo-en-python"&gt;Verificándolo en Python&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
 &lt;/li&gt;
 &lt;li&gt;&lt;a href="#el-global-interpreter-lock-gil"&gt;El Global Interpreter Lock (GIL)&lt;/a&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#el-gil-se-libera-alguna-vez"&gt;¿El GIL se libera alguna vez?&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#asyncio-y-el-gil"&gt;&lt;code&gt;asyncio&lt;/code&gt; y el GIL&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
 &lt;/li&gt;
 &lt;li&gt;&lt;a href="#concurrencia-de-un-solo-hilo"&gt;Concurrencia de Un Solo Hilo&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#cómo-funciona-el-event-loop"&gt;Cómo Funciona el Event Loop&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#en-conclusión"&gt;En conclusión&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#referencias"&gt;Referencias&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
&lt;/nav&gt;
&lt;/details&gt;

&lt;p&gt;En el &lt;a href="https://blog.dacadev.com/python/asyncio/fundamentos-asyncio"



 


&gt;artículo anterior&lt;/a&gt; construimos un modelo mental sobre concurrencia, paralelismo y los tipos de multitarea. Ahora vamos a bajar un nivel: entender qué son los procesos y los hilos, por qué el GIL de Python cambia las reglas del juego, y cómo &lt;code&gt;asyncio&lt;/code&gt; logra concurrencia con un solo hilo gracias al event loop.&lt;/p&gt;
&lt;h2 id="procesos-e-hilos"&gt;Procesos e Hilos&lt;/h2&gt;
&lt;h3 id="qué-es-un-proceso"&gt;¿Qué es un proceso?&lt;/h3&gt;
&lt;p&gt;Un &lt;strong&gt;proceso&lt;/strong&gt; es una instancia de una aplicación en ejecución. Cada proceso tiene su propio espacio de memoria aislado — ningún otro proceso puede acceder a él directamente — y se ejecuta en un CPU o núcleo del sistema.&lt;/p&gt;
&lt;h3 id="qué-es-un-hilo-thread"&gt;¿Qué es un hilo (thread)?&lt;/h3&gt;
&lt;p&gt;Un &lt;strong&gt;hilo&lt;/strong&gt; es una unidad de ejecución más ligera que vive &lt;em&gt;dentro&lt;/em&gt; de un proceso. A diferencia de los procesos, los hilos no tienen su propia memoria: comparten el espacio de memoria del proceso que los creó.&lt;/p&gt;
&lt;p&gt;Todo proceso tiene al menos un hilo asociado, conocido como el &lt;strong&gt;hilo principal&lt;/strong&gt; (&lt;em&gt;main thread&lt;/em&gt;). Además, un proceso puede crear hilos adicionales, comúnmente llamados &lt;strong&gt;hilos de trabajo&lt;/strong&gt; (&lt;em&gt;worker threads&lt;/em&gt;) o &lt;strong&gt;hilos en segundo plano&lt;/strong&gt; (&lt;em&gt;background threads&lt;/em&gt;).&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart TB
 subgraph P1[&amp;#34;Proceso (PID: 1234)&amp;#34;]
 direction TB
 M1[&amp;#34;Memoria del proceso&amp;#34;]
 MT[&amp;#34;Hilo principal\n(main thread)&amp;#34;]
 W1[&amp;#34;Worker thread 1&amp;#34;]
 W2[&amp;#34;Worker thread 2&amp;#34;]
 M1 &amp;lt;--&amp;gt; MT
 M1 &amp;lt;--&amp;gt; W1
 M1 &amp;lt;--&amp;gt; W2
 end

 style P1 fill:transparent,stroke:#64748b
 style M1 fill:#3b82f6,stroke:#1e40af,color:#fff
 style MT fill:#10b981,stroke:#065f46,color:#fff
 style W1 fill:#f59e0b,stroke:#b45309,color:#fff
 style W2 fill:#f59e0b,stroke:#b45309,color:#fff
&lt;/pre&gt;





 
 





 


&lt;div class="notice info"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Info&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Todos los hilos dentro de un proceso comparten la misma memoria. Esto hace la comunicación entre hilos muy rápida, pero introduce el riesgo de &lt;strong&gt;condiciones de carrera&lt;/strong&gt; si no se maneja con cuidado.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h3 id="verificándolo-en-python"&gt;Verificándolo en Python&lt;/h3&gt;
&lt;p&gt;Puedes inspeccionar el proceso e hilo actual con los módulos &lt;code&gt;os&lt;/code&gt; y &lt;code&gt;threading&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;os&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;threading&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#98c379"&gt;f&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;Proceso de Python con PID: &lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e06c75"&gt;os&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;getpid&lt;/span&gt;()&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;total_threads&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;threading&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;active_count&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;thread_name&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;threading&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;current_thread&lt;/span&gt;()&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#98c379"&gt;f&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;Python está ejecutando &lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e06c75"&gt;total_threads&lt;/span&gt;&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt; hilo(s)&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#98c379"&gt;f&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;El hilo actual es: &lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e06c75"&gt;thread_name&lt;/span&gt;&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#7f848e"&gt;# Output esperado&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Proceso de Python con PID: &lt;span style="color:#d19a66"&gt;48672&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Python está ejecutando &lt;span style="color:#d19a66"&gt;1&lt;/span&gt; hilo&lt;span style="color:#56b6c2"&gt;(&lt;/span&gt;s&lt;span style="color:#56b6c2"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;El hilo actual es: MainThread
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Por defecto, tu programa Python corre en un solo hilo (&lt;em&gt;MainThread&lt;/em&gt;) dentro de un solo proceso.&lt;/p&gt;
&lt;h2 id="el-global-interpreter-lock-gil"&gt;El Global Interpreter Lock (GIL)&lt;/h2&gt;
&lt;p&gt;El &lt;strong&gt;GIL&lt;/strong&gt; (&lt;em&gt;Global Interpreter Lock&lt;/em&gt;) es uno de los temas más debatidos en la comunidad Python. En términos simples: el GIL impide que un proceso de Python ejecute más de una instrucción de bytecode a la vez, incluso si tienes múltiples hilos.&lt;/p&gt;
&lt;p&gt;Esto significa que aunque crees varios hilos con &lt;code&gt;threading&lt;/code&gt;, &lt;strong&gt;solo uno ejecuta código Python en cualquier instante&lt;/strong&gt;.&lt;/p&gt;
&lt;pre class="mermaid"&gt;sequenceDiagram
 participant GIL
 participant T1 as Hilo 1
 participant T2 as Hilo 2

 GIL-&amp;gt;&amp;gt;T1: 🔓 GIL adquirido
 activate T1
 T1-&amp;gt;&amp;gt;T1: Ejecuta bytecode
 T1-&amp;gt;&amp;gt;GIL: 🔒 Libera GIL
 deactivate T1
 GIL-&amp;gt;&amp;gt;T2: 🔓 GIL adquirido
 activate T2
 T2-&amp;gt;&amp;gt;T2: Ejecuta bytecode
 T2-&amp;gt;&amp;gt;GIL: 🔒 Libera GIL
 deactivate T2
 GIL-&amp;gt;&amp;gt;T1: 🔓 GIL adquirido
 activate T1
 T1-&amp;gt;&amp;gt;T1: Ejecuta bytecode
 deactivate T1
&lt;/pre&gt;

&lt;h3 id="el-gil-se-libera-alguna-vez"&gt;¿El GIL se libera alguna vez?&lt;/h3&gt;
&lt;p&gt;Sí. El GIL &lt;strong&gt;se libera durante las operaciones de I/O&lt;/strong&gt;. Cuando un hilo hace una petición de red o una lectura de disco, libera el GIL, permitiendo que otro hilo tome el control y ejecute código Python mientras tanto.&lt;/p&gt;
&lt;p&gt;Esto es lo que hace que &lt;code&gt;threading&lt;/code&gt; sea útil para trabajo I/O-bound, pero ineficaz para trabajo CPU-bound.&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart LR
 A[&amp;#34;Operación\nCPU-bound&amp;#34;] --&amp;gt;|&amp;#34;GIL retenido 🔒&amp;#34;| B[&amp;#34;Solo 1 hilo\nejecuta a la vez&amp;#34;]
 C[&amp;#34;Operación\nI/O-bound&amp;#34;] --&amp;gt;|&amp;#34;GIL liberado 🔓&amp;#34;| D[&amp;#34;Otros hilos pueden\nejecutar código&amp;#34;]

 style A fill:#ef4444,stroke:#991b1b,color:#fff
 style B fill:#ef4444,stroke:#991b1b,color:#fff
 style C fill:#10b981,stroke:#065f46,color:#fff
 style D fill:#10b981,stroke:#065f46,color:#fff
&lt;/pre&gt;

&lt;h3 id="asyncio-y-el-gil"&gt;&lt;code&gt;asyncio&lt;/code&gt; y el GIL&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;asyncio&lt;/code&gt; aprovecha exactamente este comportamiento: como las operaciones de I/O liberan el GIL, puede lograr concurrencia &lt;strong&gt;con un solo hilo&lt;/strong&gt;. En lugar de crear múltiples hilos, &lt;code&gt;asyncio&lt;/code&gt; crea objetos llamados &lt;strong&gt;coroutines&lt;/strong&gt; — que puedes pensar como hilos ultra-ligeros.&lt;/p&gt;




 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Mientras una coroutine espera por una operación de I/O, el event loop ejecuta otras coroutines que estén listas. El resultado: concurrencia sin los problemas de sincronización del multithreading.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="concurrencia-de-un-solo-hilo"&gt;Concurrencia de Un Solo Hilo&lt;/h2&gt;
&lt;p&gt;La concurrencia de un solo hilo no se basa en hacer dos cosas simultáneamente (eso sería paralelismo), sino en &lt;strong&gt;aprovechar los tiempos de espera&lt;/strong&gt; de las operaciones de I/O para ejecutar otras tareas. El mecanismo se apoya en tres pilares:&lt;/p&gt;



&lt;div class="tab" data-tab-group=""&gt;
 &lt;ul class="tab-nav" data-tab-nav&gt;
 
 &lt;li
 class="tab-nav-item active"
 data-tab="sockets-no-bloqueantes" tabindex="0"&gt;
 Sockets no bloqueantes
 &lt;/li&gt;
 
 &lt;li
 class="tab-nav-item "
 data-tab="delegaci%C3%B3n-al-so" tabindex="-1"&gt;
 Delegación al SO
 &lt;/li&gt;
 
 &lt;li
 class="tab-nav-item "
 data-tab="event-loop" tabindex="-1"&gt;
 Event Loop
 &lt;/li&gt;
 
 &lt;/ul&gt;
 &lt;div class="tab-content" data-tab-content&gt;
 
 &lt;div
 class="tab-content-panel active"
 data-tab-panel="sockets-no-bloqueantes"&gt;
 &lt;h4 id="1-sockets-no-bloqueantes"&gt;1. Sockets no bloqueantes&lt;/h4&gt;
&lt;p&gt;A diferencia de un socket estándar que detiene el programa hasta recibir una respuesta, un &lt;strong&gt;socket no bloqueante&lt;/strong&gt; permite enviar una petición y devolver el control al programa inmediatamente, sin esperar el resultado.&lt;/p&gt;

 &lt;/div&gt;
 
 &lt;div
 class="tab-content-panel "
 data-tab-panel="delegaci%C3%B3n-al-so"&gt;
 &lt;h4 id="2-delegación-al-sistema-operativo"&gt;2. Delegación al sistema operativo&lt;/h4&gt;
&lt;p&gt;Cuando el código llega a una operación de red o lectura de disco, Python le delega la espera al sistema operativo. El hilo de ejecución queda libre de inmediato.&lt;/p&gt;

 &lt;/div&gt;
 
 &lt;div
 class="tab-content-panel "
 data-tab-panel="event-loop"&gt;
 &lt;h4 id="3-el-event-loop-como-coordinador"&gt;3. El Event Loop como coordinador&lt;/h4&gt;
&lt;p&gt;Mientras el SO vigila los sockets, el hilo de Python sigue ejecutando otras tareas. Cuando el SO detecta que los datos llegaron, envía una notificación. El event loop recibe este aviso y &amp;ldquo;despierta&amp;rdquo; la tarea pausada para que procese la respuesta.&lt;/p&gt;

 &lt;/div&gt;
 
 &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;El siguiente diagrama de secuencia muestra cómo interactúan estos tres pilares:&lt;/p&gt;
&lt;pre class="mermaid"&gt;sequenceDiagram
 participant MT as Main Thread
 participant EL as Event Loop
 participant OS as Sistema Operativo
 participant S1 as Socket 1
 participant S2 as Socket 2

 MT-&amp;gt;&amp;gt;EL: Envía tareas
 EL-&amp;gt;&amp;gt;EL: Ejecuta tarea 1 hasta I/O
 EL-&amp;gt;&amp;gt;OS: Registra Socket 1 para monitoreo
 OS-&amp;gt;&amp;gt;S1: Vigila socket
 EL-&amp;gt;&amp;gt;EL: Ejecuta tarea 2 hasta I/O
 EL-&amp;gt;&amp;gt;OS: Registra Socket 2 para monitoreo
 OS-&amp;gt;&amp;gt;S2: Vigila socket
 S1--&amp;gt;&amp;gt;OS: Datos listos ✅
 OS--&amp;gt;&amp;gt;EL: Notifica Socket 1
 EL-&amp;gt;&amp;gt;EL: Reanuda tarea 1
 S2--&amp;gt;&amp;gt;OS: Datos listos ✅
 OS--&amp;gt;&amp;gt;EL: Notifica Socket 2
 EL-&amp;gt;&amp;gt;EL: Reanuda tarea 2
&lt;/pre&gt;

&lt;h2 id="cómo-funciona-el-event-loop"&gt;Cómo Funciona el Event Loop&lt;/h2&gt;
&lt;p&gt;En su forma más básica, un event loop es simplemente un &lt;strong&gt;bucle infinito que procesa mensajes de una cola&lt;/strong&gt;, uno a la vez:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;from&lt;/span&gt; &lt;span style="color:#e06c75"&gt;collections&lt;/span&gt; &lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;deque&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;messages&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;deque&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;while&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;True&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;if&lt;/span&gt; &lt;span style="color:#e06c75"&gt;messages&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;message&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;messages&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;pop&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;process_message&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;message&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;En &lt;code&gt;asyncio&lt;/code&gt;, el event loop mantiene una cola de &lt;strong&gt;tasks&lt;/strong&gt; (tareas) en lugar de mensajes simples. Cada task es un wrapper alrededor de una coroutine. Cuando una coroutine alcanza una operación de I/O, se pausa y le devuelve el control al event loop, que puede ejecutar otras tareas que no estén esperando I/O.&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart TD
 A[&amp;#34;Event Loop inicia&amp;#34;] --&amp;gt; B[&amp;#34;¿Hay tareas en la cola?&amp;#34;]
 B --&amp;gt;|Sí| C[&amp;#34;Tomar siguiente tarea&amp;#34;]
 C --&amp;gt; D{&amp;#34;¿La tarea tiene\nI/O pendiente?&amp;#34;}
 D --&amp;gt;|No| E[&amp;#34;Ejecutar hasta\nel próximo await&amp;#34;]
 E --&amp;gt; F{&amp;#34;¿La tarea alcanzó\nuna operación I/O?&amp;#34;}
 F --&amp;gt;|Sí| G[&amp;#34;Pausar tarea y registrar\nsocket en el SO&amp;#34;]
 F --&amp;gt;|No| H[&amp;#34;Tarea completada ✅\nRemover de la cola&amp;#34;]
 G --&amp;gt; B
 H --&amp;gt; B
 D --&amp;gt;|Sí, datos listos| I[&amp;#34;Reanudar tarea&amp;#34;]
 I --&amp;gt; F
 D --&amp;gt;|Sí, esperando aún| B
 B --&amp;gt;|No| J[&amp;#34;Esperar notificaciones\ndel SO&amp;#34;]
 J --&amp;gt; B

 style A fill:#3b82f6,stroke:#1e40af,color:#fff
 style H fill:#10b981,stroke:#065f46,color:#fff
&lt;/pre&gt;





 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;Este ciclo se repite indefinidamente hasta que todas las tareas se completan o el programa se cierra explícitamente. Si una coroutine ejecuta trabajo CPU-bound sin ceder control con &lt;code&gt;await&lt;/code&gt;, &lt;strong&gt;bloqueará todo el event loop&lt;/strong&gt; y ninguna otra tarea podrá avanzar.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="en-conclusión"&gt;En conclusión&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Un &lt;strong&gt;proceso&lt;/strong&gt; tiene memoria aislada; un &lt;strong&gt;hilo&lt;/strong&gt; comparte memoria dentro de su proceso.&lt;/li&gt;
&lt;li&gt;El &lt;strong&gt;GIL&lt;/strong&gt; impide paralelismo real con hilos en Python, pero se libera durante operaciones de I/O.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;asyncio&lt;/code&gt; aprovecha esta liberación del GIL para lograr &lt;strong&gt;concurrencia en un solo hilo&lt;/strong&gt; mediante coroutines.&lt;/li&gt;
&lt;li&gt;El &lt;strong&gt;event loop&lt;/strong&gt; coordina las tareas: ejecuta coroutines hasta que alcanzan un &lt;code&gt;await&lt;/code&gt;, las pausa, y reanuda otras que ya tengan datos listos.&lt;/li&gt;
&lt;li&gt;Los &lt;strong&gt;sockets no bloqueantes&lt;/strong&gt; y la &lt;strong&gt;delegación al SO&lt;/strong&gt; son los mecanismos que permiten esta concurrencia sin crear múltiples hilos.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="referencias"&gt;Referencias&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.python.org/3/library/asyncio.html"




 target="_blank"
 


&gt;Python &lt;code&gt;asyncio&lt;/code&gt; — Documentación Oficial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.python.org/3/library/threading.html"




 target="_blank"
 


&gt;Python &lt;code&gt;threading&lt;/code&gt; — Documentación Oficial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.python.org/3/library/multiprocessing.html"




 target="_blank"
 


&gt;Python &lt;code&gt;multiprocessing&lt;/code&gt; — Documentación Oficial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://realpython.com/python-gil/"




 target="_blank"
 


&gt;Real Python — What Is the Python Global Interpreter Lock (GIL)?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://peps.python.org/pep-0703/"




 target="_blank"
 


&gt;PEP 703 — Making the Global Interpreter Lock Optional&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title>asyncio: Los Fundamentos de la Programación Asíncrona en Python</title><link>https://blog.dacadev.com/python/asyncio/fundamentos-asyncio/</link><pubDate>Sun, 10 May 2026 00:00:00 -0500</pubDate><guid>https://blog.dacadev.com/python/asyncio/fundamentos-asyncio/</guid><dc:creator>Dacadev</dc:creator><category>python</category><description>Aprende los fundamentos de asyncio en Python: diferencia entre concurrencia y paralelismo, operaciones CPU-bound vs I/O-bound, y cómo funciona la multitarea cooperativa.</description><media:content url="https://blog.dacadev.com/images/python/asyncio/fundamentals/banner.png" medium="image" type="image/png"/><content:encoded>
&lt;details class="table-of-content "&gt;
 &lt;summary&gt;
 
 Tabla de Contenido
 
 &lt;/summary&gt;
 &lt;nav id="TableOfContents"&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#qué-es-la-programación-asíncrona"&gt;¿Qué es la programación asíncrona?&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#cpu-bound-vs-io-bound"&gt;CPU-bound vs. I/O-bound&lt;/a&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#operaciones-limitadas-por-es-io-bound"&gt;Operaciones limitadas por E/S (I/O-bound)&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#operaciones-limitadas-por-cpu-cpu-bound"&gt;Operaciones limitadas por CPU (CPU-bound)&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#ejemplo-práctico"&gt;Ejemplo práctico&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
 &lt;/li&gt;
 &lt;li&gt;&lt;a href="#concurrencia-vs-paralelismo"&gt;Concurrencia vs. Paralelismo&lt;/a&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#concurrencia-alternar-entre-tareas"&gt;Concurrencia: alternar entre tareas&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#paralelismo-ejecución-simultánea-real"&gt;Paralelismo: ejecución simultánea real&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
 &lt;/li&gt;
 &lt;li&gt;&lt;a href="#tipos-de-multitarea"&gt;Tipos de Multitarea&lt;/a&gt;
 &lt;ol&gt;
 &lt;li&gt;&lt;a href="#multitarea-preventiva-preemptive"&gt;Multitarea preventiva (Preemptive)&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#multitarea-cooperativa-cooperative"&gt;Multitarea cooperativa (Cooperative)&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#comparación-rápida"&gt;Comparación rápida&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
 &lt;/li&gt;
 &lt;li&gt;&lt;a href="#dónde-encaja-asyncio"&gt;¿Dónde encaja &lt;code&gt;asyncio&lt;/code&gt;?&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#en-conclusión"&gt;En conclusión&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#referencias"&gt;Referencias&lt;/a&gt;&lt;/li&gt;
 &lt;/ol&gt;
&lt;/nav&gt;
&lt;/details&gt;

&lt;p&gt;Si alguna vez construiste un scraper que recorre decenas de páginas, un microservicio que atiende cientos de peticiones o un bot que consume múltiples APIs, seguro sentiste la frustración de esperar. Una petición termina, la siguiente arranca, y tu programa queda ahí sin hacer nada útil.&lt;/p&gt;
&lt;p&gt;La librería &lt;code&gt;asyncio&lt;/code&gt; de Python fue diseñada para resolver exactamente este problema. En este artículo vamos a construir un modelo mental sólido sobre los conceptos clave: concurrencia, paralelismo, multitarea y la diferencia entre operaciones limitadas por CPU y por E/S.&lt;/p&gt;
&lt;h2 id="qué-es-la-programación-asíncrona"&gt;¿Qué es la programación asíncrona?&lt;/h2&gt;
&lt;p&gt;La &lt;strong&gt;programación asíncrona&lt;/strong&gt; es un modelo donde las tareas de larga duración se ejecutan en segundo plano, separadas del flujo principal de tu aplicación. En lugar de bloquear todo mientras esperas una respuesta de red o una lectura de archivo, el sistema queda libre para hacer otro trabajo. Cuando la tarea termina, tu código recibe una notificación y puede procesar el resultado.&lt;/p&gt;




 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;code&gt;asyncio&lt;/code&gt; — abreviación de &lt;strong&gt;asynchronous I/O&lt;/strong&gt; — es la librería estándar de Python que implementa este modelo. Fue introducida en &lt;a href="https://docs.python.org/3/library/asyncio.html"




 target="_blank"
 


&gt;Python 3.4&lt;/a&gt; y hoy es la base de frameworks modernos como &lt;a href="https://fastapi.tiangolo.com/"




 target="_blank"
 


&gt;FastAPI&lt;/a&gt;, &lt;a href="https://docs.aiohttp.org/"




 target="_blank"
 


&gt;aiohttp&lt;/a&gt; y &lt;a href="https://www.starlette.io/"




 target="_blank"
 


&gt;Starlette&lt;/a&gt;.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="cpu-bound-vs-io-bound"&gt;CPU-bound vs. I/O-bound&lt;/h2&gt;
&lt;p&gt;Antes de avanzar, necesitas entender una distinción fundamental: &lt;strong&gt;¿en qué está gastando tiempo tu código?&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="operaciones-limitadas-por-es-io-bound"&gt;Operaciones limitadas por E/S (I/O-bound)&lt;/h3&gt;
&lt;p&gt;Tu programa pasa la mayor parte del tiempo &lt;strong&gt;esperando un sistema externo&lt;/strong&gt;: la red, el disco, una base de datos. La CPU está prácticamente ociosa. Ejemplos:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hacer peticiones HTTP.&lt;/li&gt;
&lt;li&gt;Leer o escribir archivos en disco.&lt;/li&gt;
&lt;li&gt;Consultar una base de datos.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="operaciones-limitadas-por-cpu-cpu-bound"&gt;Operaciones limitadas por CPU (CPU-bound)&lt;/h3&gt;
&lt;p&gt;El &lt;strong&gt;procesador&lt;/strong&gt; es el cuello de botella. La CPU está activamente calculando, sin esperas externas. Ejemplos:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Calcular dígitos de pi.&lt;/li&gt;
&lt;li&gt;Aplicar lógica de negocio sobre estructuras de datos grandes.&lt;/li&gt;
&lt;li&gt;Procesamiento de imágenes o entrenamiento de modelos.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="ejemplo-práctico"&gt;Ejemplo práctico&lt;/h3&gt;
&lt;p&gt;Considera este fragmento de código:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;requests&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;response&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;requests&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;get&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;https://www.example.com&amp;#39;&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# 1 - I/O-bound&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;items&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#e06c75"&gt;response&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;headers&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;items&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;headers&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; [&lt;span style="color:#98c379"&gt;f&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e06c75"&gt;key&lt;/span&gt;&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt;: &lt;/span&gt;&lt;span style="color:#98c379"&gt;{&lt;/span&gt;&lt;span style="color:#e06c75"&gt;header&lt;/span&gt;&lt;span style="color:#98c379"&gt;}&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;&lt;/span&gt; &lt;span style="color:#c678dd"&gt;for&lt;/span&gt; &lt;span style="color:#e06c75"&gt;key&lt;/span&gt;, &lt;span style="color:#e06c75"&gt;header&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;in&lt;/span&gt; &lt;span style="color:#e06c75"&gt;items&lt;/span&gt;] &lt;span style="color:#7f848e"&gt;# 2 - CPU-bound&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;formatted_headers&lt;/span&gt; &lt;span style="color:#56b6c2"&gt;=&lt;/span&gt; &lt;span style="color:#98c379"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#98c379"&gt;\n&lt;/span&gt;&lt;span style="color:#98c379"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;join&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;headers&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# 3 - CPU-bound&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;with&lt;/span&gt; &lt;span style="color:#e5c07b"&gt;open&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#39;headers.txt&amp;#39;&lt;/span&gt;, &lt;span style="color:#98c379"&gt;&amp;#39;w&amp;#39;&lt;/span&gt;) &lt;span style="color:#c678dd"&gt;as&lt;/span&gt; &lt;span style="color:#e06c75"&gt;file&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e06c75"&gt;file&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;write&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;formatted_headers&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# 4 - I/O-bound&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;El siguiente diagrama muestra el flujo de ejecución y clasifica cada paso:&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart LR
 A[&amp;#34;1. requests.get()&amp;#34;] --&amp;gt;|respuesta| B[&amp;#34;2. List comprehension&amp;#34;]
 B --&amp;gt; C[&amp;#34;3. join() headers&amp;#34;]
 C --&amp;gt; D[&amp;#34;4. file.write()&amp;#34;]

 style A fill:#3b82f6,stroke:#1e40af,color:#fff
 style B fill:#f59e0b,stroke:#b45309,color:#fff
 style C fill:#f59e0b,stroke:#b45309,color:#fff
 style D fill:#3b82f6,stroke:#1e40af,color:#fff
&lt;/pre&gt;

&lt;blockquote&gt;
&lt;p&gt;🔵 &lt;strong&gt;Azul = I/O-bound&lt;/strong&gt; (esperando red o disco) · 🟡 &lt;strong&gt;Amarillo = CPU-bound&lt;/strong&gt; (procesando en memoria)&lt;/p&gt;
&lt;/blockquote&gt;




 
 





 


&lt;div class="notice info"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" width="22" height="22"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Info&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;&lt;code&gt;asyncio&lt;/code&gt; brilla con cargas &lt;strong&gt;I/O-bound&lt;/strong&gt;. Si tu cuello de botella es la CPU, necesitarás &lt;code&gt;multiprocessing&lt;/code&gt; o &lt;a href="https://docs.python.org/3/library/concurrent.futures.html"




 target="_blank"
 


&gt;concurrent.futures&lt;/a&gt;.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="concurrencia-vs-paralelismo"&gt;Concurrencia vs. Paralelismo&lt;/h2&gt;
&lt;p&gt;Estos dos términos se confunden constantemente, pero describen cosas distintas.&lt;/p&gt;
&lt;h3 id="concurrencia-alternar-entre-tareas"&gt;Concurrencia: alternar entre tareas&lt;/h3&gt;
&lt;p&gt;Concurrencia significa &lt;strong&gt;gestionar múltiples tareas en períodos de tiempo superpuestos&lt;/strong&gt;, sin necesidad de ejecutarlas en el mismo instante. Piensa en un chef preparando dos platos: pica verduras para el plato A, lo mete al horno y empieza a trabajar en el plato B mientras el A se cocina. Solo hace una cosa a la vez, pero ambos platos avanzan.&lt;/p&gt;
&lt;p&gt;En un sistema concurrente, una sola CPU alterna entre tareas. Mientras la tarea #1 espera por E/S, la CPU toma la tarea #2.&lt;/p&gt;
&lt;pre class="mermaid"&gt;gantt
 title Concurrencia — Una sola CPU alternando entre tareas
 dateFormat X
 axisFormat %s

 section CPU
 App #1 :a1, 0, 2
 App #2 :a2, 2, 4
 App #1 :a3, 4, 6
 App #2 :a4, 6, 8
 App #1 :a5, 8, 10
&lt;/pre&gt;

&lt;h3 id="paralelismo-ejecución-simultánea-real"&gt;Paralelismo: ejecución simultánea real&lt;/h3&gt;
&lt;p&gt;Paralelismo significa &lt;strong&gt;ejecutar múltiples tareas al mismo tiempo&lt;/strong&gt;, lo cual requiere múltiples CPUs o núcleos.&lt;/p&gt;
&lt;pre class="mermaid"&gt;gantt
 title Paralelismo — Múltiples CPUs ejecutando simultáneamente
 dateFormat X
 axisFormat %s

 section CPU 1
 App #1 :a1, 0, 10

 section CPU 2
 App #2 :b1, 0, 10
&lt;/pre&gt;

&lt;p&gt;En palabras de Rob Pike (co-creador de Go): &lt;em&gt;&amp;ldquo;La concurrencia se trata de lidiar con muchas cosas a la vez. El paralelismo se trata de hacer muchas cosas a la vez.&amp;rdquo;&lt;/em&gt;&lt;/p&gt;




 
 





 


&lt;div class="notice note"&gt;
 &lt;div class="notice-head"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="22" height="22" stroke-width="1.5" stroke="currentColor"&gt;
 &lt;path stroke-linecap="round" stroke-linejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125" /&gt;
 &lt;/svg&gt;
 &lt;p&gt;Note&lt;/p&gt;
 
 &lt;/div&gt;
 &lt;div class="notice-body"&gt;&lt;p&gt;La concurrencia es un &lt;strong&gt;patrón de diseño&lt;/strong&gt;; el paralelismo es un &lt;strong&gt;modelo de ejecución&lt;/strong&gt;. &lt;code&gt;asyncio&lt;/code&gt; logra concurrencia en un solo hilo, sin paralelismo.&lt;/p&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="tipos-de-multitarea"&gt;Tipos de Multitarea&lt;/h2&gt;
&lt;p&gt;Existen dos enfoques principales para la multitarea, y entender la diferencia es clave para comprender dónde encaja &lt;code&gt;asyncio&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="multitarea-preventiva-preemptive"&gt;Multitarea preventiva (Preemptive)&lt;/h3&gt;
&lt;p&gt;El &lt;strong&gt;sistema operativo&lt;/strong&gt; decide cuándo cambiar entre tareas mediante un mecanismo llamado &lt;strong&gt;time slicing&lt;/strong&gt;: divide el tiempo de CPU en intervalos pequeños y rota entre las tareas activas. Cuando el SO fuerza un cambio, se dice que está haciendo &lt;em&gt;preemption&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;En Python, este es el modelo que usan los módulos &lt;code&gt;threading&lt;/code&gt; (hilos) y &lt;code&gt;multiprocessing&lt;/code&gt; (procesos). La ventaja es que no tienes que pensar en cuándo ceder el control. La desventaja: los cambios pueden ocurrir en cualquier momento, lo que introduce &lt;strong&gt;condiciones de carrera&lt;/strong&gt; y la necesidad de &lt;strong&gt;locks&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id="multitarea-cooperativa-cooperative"&gt;Multitarea cooperativa (Cooperative)&lt;/h3&gt;
&lt;p&gt;Las &lt;strong&gt;propias tareas&lt;/strong&gt; deciden cuándo ceder el control. Cada tarea señala explícitamente: &lt;em&gt;&amp;ldquo;Me pauso aquí, ejecuta otras tareas.&amp;rdquo;&lt;/em&gt; No hay intervención del SO.&lt;/p&gt;
&lt;p&gt;Este es exactamente el modelo de &lt;code&gt;asyncio&lt;/code&gt;. En Python, la palabra clave &lt;code&gt;await&lt;/code&gt; es esa señal explícita:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#abb2bf;background-color:#282c34;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;import&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;obtener_datos&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;Obteniendo datos...&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;await&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;sleep&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;2&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# 👈 &amp;#34;Me pauso aquí, ejecuta otras tareas&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;Datos obtenidos!&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;procesar_datos&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;Procesando datos...&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;await&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;sleep&lt;/span&gt;(&lt;span style="color:#d19a66"&gt;1&lt;/span&gt;) &lt;span style="color:#7f848e"&gt;# 👈 Misma señal&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e5c07b"&gt;print&lt;/span&gt;(&lt;span style="color:#98c379"&gt;&amp;#34;Datos procesados!&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#c678dd"&gt;async&lt;/span&gt; &lt;span style="color:#c678dd"&gt;def&lt;/span&gt; &lt;span style="color:#61afef;font-weight:bold"&gt;main&lt;/span&gt;():
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#c678dd"&gt;await&lt;/span&gt; &lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;gather&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;obtener_datos&lt;/span&gt;(), &lt;span style="color:#e06c75"&gt;procesar_datos&lt;/span&gt;())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e06c75"&gt;asyncio&lt;/span&gt;&lt;span style="color:#56b6c2"&gt;.&lt;/span&gt;&lt;span style="color:#e06c75"&gt;run&lt;/span&gt;(&lt;span style="color:#e06c75"&gt;main&lt;/span&gt;())
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;La ventaja es la &lt;strong&gt;predictibilidad&lt;/strong&gt;: tú controlas exactamente dónde ocurren los cambios. El riesgo: si una tarea olvida hacer &lt;code&gt;await&lt;/code&gt; o ejecuta una operación CPU-bound larga sin ceder control, bloquea todo el event loop.&lt;/p&gt;
&lt;p&gt;El siguiente diagrama de secuencia ilustra cómo el event loop coordina las tareas cooperativamente:&lt;/p&gt;
&lt;pre class="mermaid"&gt;sequenceDiagram
 participant EL as Event Loop
 participant T1 as obtener_datos()
 participant T2 as procesar_datos()

 EL-&amp;gt;&amp;gt;T1: Ejecutar
 T1-&amp;gt;&amp;gt;EL: await sleep(2) — cede control
 EL-&amp;gt;&amp;gt;T2: Ejecutar
 T2-&amp;gt;&amp;gt;EL: await sleep(1) — cede control
 EL-&amp;gt;&amp;gt;T2: sleep completado — reanudar
 T2-&amp;gt;&amp;gt;EL: Finalizada ✅
 EL-&amp;gt;&amp;gt;T1: sleep completado — reanudar
 T1-&amp;gt;&amp;gt;EL: Finalizada ✅
&lt;/pre&gt;

&lt;h3 id="comparación-rápida"&gt;Comparación rápida&lt;/h3&gt;



&lt;div class="tab" data-tab-group=""&gt;
 &lt;ul class="tab-nav" data-tab-nav&gt;
 
 &lt;li
 class="tab-nav-item active"
 data-tab="preventiva" tabindex="0"&gt;
 Preventiva
 &lt;/li&gt;
 
 &lt;li
 class="tab-nav-item "
 data-tab="cooperativa" tabindex="-1"&gt;
 Cooperativa
 &lt;/li&gt;
 
 &lt;/ul&gt;
 &lt;div class="tab-content" data-tab-content&gt;
 
 &lt;div
 class="tab-content-panel active"
 data-tab-panel="preventiva"&gt;
 &lt;h4 id="multitarea-preventiva"&gt;Multitarea Preventiva&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;¿Quién cambia?&lt;/strong&gt; El Sistema Operativo&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mecanismo:&lt;/strong&gt; Time slicing&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Herramientas en Python:&lt;/strong&gt; &lt;code&gt;threading&lt;/code&gt;, &lt;code&gt;multiprocessing&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Riesgo principal:&lt;/strong&gt; Condiciones de carrera&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ideal para:&lt;/strong&gt; Cargas CPU-bound o mixtas&lt;/li&gt;
&lt;/ul&gt;

 &lt;/div&gt;
 
 &lt;div
 class="tab-content-panel "
 data-tab-panel="cooperativa"&gt;
 &lt;h4 id="multitarea-cooperativa"&gt;Multitarea Cooperativa&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;¿Quién cambia?&lt;/strong&gt; La propia tarea&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mecanismo:&lt;/strong&gt; &lt;code&gt;await&lt;/code&gt; / yield&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Herramientas en Python:&lt;/strong&gt; &lt;code&gt;asyncio&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Riesgo principal:&lt;/strong&gt; Bloquear el event loop&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ideal para:&lt;/strong&gt; Cargas I/O-bound&lt;/li&gt;
&lt;/ul&gt;

 &lt;/div&gt;
 
 &lt;/div&gt;
&lt;/div&gt;

&lt;h2 id="dónde-encaja-asyncio"&gt;¿Dónde encaja &lt;code&gt;asyncio&lt;/code&gt;?&lt;/h2&gt;
&lt;p&gt;Con todos estos conceptos claros, el siguiente diagrama te ayuda a decidir qué herramienta usar según tu caso:&lt;/p&gt;
&lt;pre class="mermaid"&gt;flowchart TD
 A[&amp;#34;¿Qué tipo de operación\nnecesitas optimizar?&amp;#34;] --&amp;gt; B{&amp;#34;¿Es I/O-bound?&amp;#34;}
 B --&amp;gt;|Sí| C{&amp;#34;¿Necesitas manejar\nmuchas conexiones?&amp;#34;}
 C --&amp;gt;|Sí| D[&amp;#34;✅ asyncio&amp;#34;]
 C --&amp;gt;|No| E[&amp;#34;threading o\nasyncio&amp;#34;]
 B --&amp;gt;|No| F{&amp;#34;¿Es CPU-bound?&amp;#34;}
 F --&amp;gt;|Sí| G{&amp;#34;¿Necesitas compartir\nmemoria entre tareas?&amp;#34;}
 G --&amp;gt;|Sí| H[&amp;#34;threading\n+ locks&amp;#34;]
 G --&amp;gt;|No| I[&amp;#34;multiprocessing&amp;#34;]
 F --&amp;gt;|Mixto| J[&amp;#34;asyncio +\nrun_in_executor()&amp;#34;]

 style D fill:#10b981,stroke:#065f46,color:#fff
 style E fill:#10b981,stroke:#065f46,color:#fff
 style H fill:#f59e0b,stroke:#b45309,color:#fff
 style I fill:#3b82f6,stroke:#1e40af,color:#fff
 style J fill:#8b5cf6,stroke:#5b21b6,color:#fff
&lt;/pre&gt;

&lt;h2 id="en-conclusión"&gt;En conclusión&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;asyncio&lt;/code&gt; ofrece &lt;strong&gt;concurrencia&lt;/strong&gt;, no paralelismo — todo corre en un solo hilo.&lt;/li&gt;
&lt;li&gt;Usa &lt;strong&gt;multitarea cooperativa&lt;/strong&gt; — tu código cede control explícitamente con &lt;code&gt;await&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Destaca en cargas &lt;strong&gt;I/O-bound&lt;/strong&gt; — peticiones de red, operaciones de archivo, consultas a bases de datos.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No es la solución&lt;/strong&gt; para trabajo CPU-bound — para eso, combínalo con &lt;code&gt;multiprocessing&lt;/code&gt; o usa &lt;a href="https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.loop.run_in_executor"




 target="_blank"
 


&gt;loop.run_in_executor()&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="referencias"&gt;Referencias&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.python.org/3/library/asyncio.html"




 target="_blank"
 


&gt;Python &lt;code&gt;asyncio&lt;/code&gt; — Documentación Oficial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.python.org/3/library/concurrent.futures.html"




 target="_blank"
 


&gt;Python &lt;code&gt;concurrent.futures&lt;/code&gt; — Documentación Oficial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://realpython.com/async-io-python/"




 target="_blank"
 


&gt;Real Python — Async IO in Python: A Complete Walkthrough&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://peps.python.org/pep-3156/"




 target="_blank"
 


&gt;PEP 3156 — Asynchronous IO Support Rebooted&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item></channel></rss>