Programación asíncrona en Python

Mar 06 2023
La programación asincrónica es un paradigma de programación que permite que muchos procesos se realicen de forma simultánea e independiente, sin esperar a que uno termine antes de pasar al siguiente. En esta publicación de blog, veremos qué es la programación asíncrona y cómo usarla en python.
Programación asíncrona en Python

La programación asincrónica es un paradigma de programación que permite que muchos procesos se realicen de forma simultánea e independiente, sin esperar a que uno termine antes de pasar al siguiente. En esta publicación de blog, veremos qué es la programación asíncrona y cómo usarla en python.

¿Qué es la programación asincrónica?

En la programación síncrona, la computadora ejecuta instrucciones en orden secuencial, bloqueando la ejecución hasta que se completa un trabajo antes de pasar al siguiente.
La programación asincrónica, por otro lado, permite que el programa comience una operación y luego continúe con otra sin detener la ejecución hasta que se complete la tarea original.

La programación asíncrona es especialmente beneficiosa en circunstancias en las que los procesos, como la E/S de la red o las operaciones de la base de datos, pueden tardar mucho tiempo en completarse. La programación asincrónica puede ayudar a aumentar el rendimiento y la capacidad de respuesta en las aplicaciones de software al permitir que el programa continúe con otras actividades mientras espera que se complete una operación lenta.

Según el lenguaje de programación y el marco utilizado, la programación asíncrona se puede lograr mediante varias estrategias, como devoluciones de llamada, promesas o palabras clave asíncronas/en espera.

Diferencias entre programación asíncrona y multiprocesamiento

La principal diferencia entre la programación asíncrona y el multiprocesamiento es que la programación asíncrona permite que ocurran operaciones sin bloqueo dentro de un solo hilo, mientras que el multiprocesamiento usa muchos núcleos o procesos para completar el trabajo simultáneamente.

Diferencias entre programación asincrónica y subprocesamiento

La principal diferencia entre la programación asíncrona y la creación de subprocesos es que la programación asíncrona permite operaciones sin bloqueo mediante el uso de un único subproceso, mientras que la creación de subprocesos utiliza varios subprocesos para realizar varias tareas en paralelo.

Para más información sobre las diferencias: Treading vs Multiprocessing vs Asynchronous Programming

¿Cómo usar Asyncio?

Primero, hagamos un programa simple que comience a hacer un trabajo a la vez y los termine.

import time
import asyncio

def do_job(s):
    print(f"{s} started")
    await asyncio.sleep(1)
    print(f"{s} done")

def main():
    start = time.perf_counter()
    todo = ["Job A", "Job B", "Job C"]
    for job in todo:
        do_job(job)
    
    end = time.perf_counter()
    print(f"Took: {end-start:.3f} seconds")

main()

# OUTPUT
# Job A started
# Job Adone
# Job B started
# Job B done
# Job C started
# Job C done
# Took: 3.009 seconds

Creación y ejecución de rutinas

Una rutina es un tipo de función que se puede interrumpir y reanudar en varios momentos durante la ejecución. En otras palabras, una corrutina le permite escribir código que se puede interrumpir, hacer otra cosa y luego continuar donde lo dejó.

Para crear rutinas, necesitamos usar la asyncpalabra clave antes de la defpalabra clave. Llamar a una rutina no llama a la función que queremos ejecutar. Crea una tarea.

import time
import asyncio

async def do_job(s):
  ...

async def main():
  ...

main()

asyncio.run(main())

si ejecuta este código, probablemente obtenga un error como este:

RuntimeWarning: coroutine '...' was never awaited

import time
import asyncio

async def do_job(s):
    print(f"{s} started")
    await asyncio.sleep(1)
    print(f"{s} done")

async def main():
    start = time.perf_counter()
    todo = ["Job A", "Job B", "Job C"]
    for job in todo:
        await do_job(job)
    
    end = time.perf_counter()
    print(f"Took: {end-start:.3f} seconds")

asyncio.run(main())

# OUTPUT
# Job A started
# Job A done
# Job B started
# Job B done
# Job C started
# Job C done
# Took: 3.009 seconds

await asyncio.sleep(1)

tasks = [asyncio.create_task(do_job(item)) for item in todo]
done, pending = await asyncio.wait(tasks)

import time
import asyncio

async def do_job(s):
    print(f"{s} started")
    await asyncio.sleep(1)
    print(f"{s} done")

async def main():
    start = time.perf_counter()
    todo = ["Job A", "Job B", "Job C"]
    
    tasks = [asyncio.create_task(do_job(item)) for item in todo]
    done, pending = await asyncio.wait(tasks)
    
    end = time.perf_counter()
    print(f"Took: {end-start:.3f} seconds")

asyncio.run(main())

# OUTPUT
# Job A started
# Job B started
# Job C started
# Job A done
# Job B done
# Job C done
# Took: 1.009 seconds

Puede ver el video para obtener más información sobre la programación asíncrona en python. ( Introducción a Python asíncrono | Escritura de un rastreador web )