Python: espere a que se complete la función asíncrona

Salman Mehmood 15 febrero 2024
  1. Use la palabra clave await y cree una función asíncrona
  2. Use create_task() para crear una tarea para solucionar un problema
Python: espere a que se complete la función asíncrona

Este artículo demuestra cómo crear una función asíncrona y usar la palabra clave await para interrumpir un proceso. También ‘aprenderemos a usar tareas en lugar de hilos en Python.

Use la palabra clave await y cree una función asíncrona

La programación asíncrona no es multihilo; no es multiprocesamiento sino programación concurrente.

No hablaremos sobre la idea completa de la programación concurrente y el patrón de codificación completo, pero hablaremos sobre los principios básicos y cómo podemos implementarlos en Python.

Ahora veamos un ejemplo rápido; tenemos un Func_1, Func_2 y Func_3, que están siendo llamados.

Func_1()
Func_2()
Func_3()

Si estas funciones se llaman de forma asíncrona, esto significa que vamos a llamar a Func_1() y luego vamos a llamar a Func_2().

Cuando regrese Func_1(), solo llamaremos a Func_2(), y cuando regrese Func_2(), llamaremos a Func_3().

Si usamos subprocesos múltiples o procesamiento múltiple, eso no sería lo mismo que la programación asíncrona. Porque en subprocesos múltiples, definiríamos tres subprocesos en este caso, y ejecutaríamos todas estas funciones al mismo tiempo.

O, más o menos simultáneamente, intentaremos ejecutarlos simultáneamente o al menos crear la ilusión de una ejecución simultánea.

Pero, queremos hacer, digamos, Func_1() hace algo productivo, y luego solicita algunos datos de una base de datos, de una API, o simplemente duerme en general solo por el hecho de esperar.

Si eso sucede, no queremos perder tiempo de CPU y comenzar a ejecutar Func_2() aunque esta función aún no haya regresado. Entonces solo podemos ejecutar una tarea simultáneamente; no estamos haciendo ningún procesamiento múltiple o subprocesamiento múltiple.

Pero, si Func_1() está durmiendo o esperando o siendo improductivo, podemos utilizar ese tiempo para comenzar a ejecutar Func_2() y tal vez Func_3(). Para hacer programación asíncrona en Python, debemos importar una librería llamada asyncio.

Dado que no definiremos todo el programa como asíncrono, las funciones específicas serán asíncronas; necesitamos usar la palabra clave async para especificar una función asíncrona.

Si solo tenemos esta Main_Func(), todo el programa será asíncrono, pero agregaremos otras funciones en el siguiente ejemplo. Dentro de esta función, utilizaremos dos funciones print().

Y, de por medio, nos vamos a dormir, pero no nos vamos a dormir con time.sleep(); vamos a utilizar asyncio.sleep().

Necesitamos usar la palabra clave await antes de llamar a asyncio.sleep(), lo que significa que esperaremos a que termine la segunda declaración de impresión. Antes de terminar, no vamos a hacer nada más.

Para ejecutar la función Main_Func() necesitamos usar asyncio.run() y dentro de la función run() pasaremos la función Main_Func(). Debemos llamar a la función Main_Func(); no solo nos referimos a él como subprocesos múltiples.

import asyncio


async def Main_Func():
    print("Before waiting")
    await asyncio.sleep(1)
    print("After waiting")


asyncio.run(Main_Func())

Producción:

python espere a que se complete la función asíncrona - salida uno

Introduzcamos otra función asíncrona llamada Func_2(); imprimiremos dos declaraciones y dormiremos durante dos segundos.

Dentro de la función Main_Func(), en lugar de dormir, llamamos a la función Func_2() con la palabra clave await, pero eso no será asíncrono.

import asyncio


async def Main_Func():
    print("Before waiting")
    await Func_2()
    print("After waiting")


async def Func_2():
    print("Func_2: Before waiting")
    await asyncio.sleep(2)
    print("Func_2: After waiting")


asyncio.run(Main_Func())

Dado que estamos esperando la función, que es lo mismo que simplemente llamarla de forma asíncrona, no la ejecutará hasta que todas las instrucciones se completen como definimos.

Before waiting
Func_2: Before waiting
Func_2: After waiting
After waiting

No es asíncrono; sin embargo, si queremos hacer algo así cuando llama la función Main_Func(), entonces el control debe imprimir la primera declaración print de la función Main_Func().

Y luego, llame a la función Func_2(), imprimiendo así la primera declaración print de esta función.

Mientras esta función está durmiendo, debe imprimir la segunda instrucción print de la función Main_Func(), y una vez hecho esto, debe imprimir la segunda declaración print de la función Func_2().

Use create_task() para crear una tarea para solucionar un problema

Para hacer eso, necesitamos trabajar con tareas, por lo que, al comienzo de la función Main_Func(), vamos a crear una tarea mientras llamamos a asyncio.create_task(), y dentro de la tarea, haremos pasar Func_2().

Significa que una vez que tengamos algo de tiempo libre, llamaremos a esa tarea.

import asyncio


async def Main_Func():
    Task = asyncio.create_task(Func_2())
    print("Before waiting")
    print("After waiting")


async def Func_2():
    print("Func_2: Before waiting")
    await asyncio.sleep(2)
    print("Func_2: After waiting")


asyncio.run(Main_Func())

Después de ejecutar el código, podemos ver que las dos declaraciones de impresión se imprimen desde la función Main_Func() y luego está listo. Y se ejecuta la primera sentencia print, pero la ejecución finaliza antes de imprimir la segunda sentencia print.

Before waiting
After waiting
Func_2: Before waiting

Debido a que Main_Func() es la función principal, el control no está esperando la función Func_2(), lo que significa que una vez que el control llega al final de la función Main_Func(), el control deja de ejecutarse. .

El control no necesita esperar a que termine la segunda instrucción print de la función Func_2() para que el control la salte. Para arreglarlo, usaremos await Task al final de la función Main_Func().

import asyncio


async def Main_Func():
    Task = asyncio.create_task(Func_2())
    print("Before waiting")
    print("After waiting")
    await Task


async def Func_2():
    print("Func_2: Before waiting")
    await asyncio.sleep(2)
    print("Func_2: After waiting")


asyncio.run(Main_Func())

Ahora podemos ver que se imprime como se definió.

Before waiting
After waiting
Func_2: Before waiting
Func_2: After waiting

Si queremos ver cómo funciona esto de forma asíncrona, podemos hacerlo usando la función sleep() entre las sentencias print.

Significa que ejecutaremos una primera declaración de print de Main_Func(), y luego el control dormirá por un segundo, lo que significa que la función principal ahora tiene tiempo de inactividad.

Y ahora, la tarea tiene tiempo para ejecutarse hasta que Main_Func() se ejecute por completo. Dado que la función Main_Func() está inactiva, significa que ahora tenemos tiempo de CPU disponible para comenzar a ejecutar la función Func_2() llamándola usando la tarea.

Pero, la función Func_2() también se duerme, lo que significa que dentro de esta función el control espera dos segundos, y el control va a la función Main_Func() para imprimir una segunda declaración print.

Luego termina, lo que significa que el control ya no está interesado en el resto de la función Func_2().

async def Main_Func():
    Task = asyncio.create_task(Func_2())
    print("Before waiting")
    await asyncio.sleep(1)
    print("After waiting")

Producción :

Before waiting
Func_2: Before waiting
After waiting

Si queremos estar interesados en eso, tenemos que usar await Task al final de la función Main_Func().

Es asíncrono; como puede ver, el orden es que la función Main_Func() imprime la primera instrucción print, luego Func_2() imprime primero, luego Main_Func() imprime la segunda así como Func_2() imprime el segundo.

Porque cuando la función entra en suspensión, se utiliza el tiempo de inactividad para que no se desperdicie tiempo de CPU.

python espere a que se complete la función asíncrona - salida dos

Salman Mehmood avatar Salman Mehmood avatar

Hello! I am Salman Bin Mehmood(Baum), a software developer and I help organizations, address complex problems. My expertise lies within back-end, data science and machine learning. I am a lifelong learner, currently working on metaverse, and enrolled in a course building an AI application with python. I love solving problems and developing bug-free software for people. I write content related to python and hot Technologies.

LinkedIn

Artículo relacionado - Python Async