Programación basada en eventos

La programación impulsada por eventos se centra en eventos. Finalmente, el flujo del programa depende de los eventos. Hasta ahora, estábamos tratando con un modelo de ejecución secuencial o paralelo, pero el modelo que tiene el concepto de programación dirigida por eventos se llama modelo asincrónico. La programación impulsada por eventos depende de un bucle de eventos que siempre está atento a los nuevos eventos entrantes. El funcionamiento de la programación impulsada por eventos depende de los eventos. Una vez que un evento se repite, los eventos deciden qué ejecutar y en qué orden. El siguiente diagrama de flujo lo ayudará a comprender cómo funciona esto:

Módulo Python - Asyncio

El módulo Asyncio se agregó en Python 3.4 y proporciona infraestructura para escribir código concurrente de un solo subproceso utilizando co-rutinas. A continuación se muestran los diferentes conceptos utilizados por el módulo Asyncio:

El bucle de eventos

Event-loop es una funcionalidad para manejar todos los eventos en un código computacional. Actúa durante la ejecución de todo el programa y realiza un seguimiento de la entrada y ejecución de eventos. El módulo Asyncio permite un único bucle de eventos por proceso. Los siguientes son algunos métodos proporcionados por el módulo Asyncio para administrar un bucle de eventos:

  • loop = get_event_loop() - Este método proporcionará el bucle de eventos para el contexto actual.

  • loop.call_later(time_delay,callback,argument) - Este método organiza la devolución de llamada que se llamará después de los segundos de time_delay dados.

  • loop.call_soon(callback,argument)- Este método organiza una devolución de llamada que se llamará lo antes posible. La devolución de llamada se llama después de que call_soon () regresa y cuando el control regresa al bucle de eventos.

  • loop.time() - Este método se utiliza para devolver la hora actual de acuerdo con el reloj interno del bucle de eventos.

  • asyncio.set_event_loop() - Este método establecerá el ciclo de eventos para el contexto actual en el ciclo.

  • asyncio.new_event_loop() - Este método creará y devolverá un nuevo objeto de bucle de eventos.

  • loop.run_forever() - Este método se ejecutará hasta que se llame al método stop ().

Ejemplo

El siguiente ejemplo de bucle de eventos ayuda a imprimir hello worldutilizando el método get_event_loop (). Este ejemplo está tomado de los documentos oficiales de Python.

import asyncio

def hello_world(loop):
   print('Hello World')
   loop.stop()

loop = asyncio.get_event_loop()

loop.call_soon(hello_world, loop)

loop.run_forever()
loop.close()

Salida

Hello World

Futuros

Esto es compatible con la clase concurrent.futures.Future que representa un cálculo que no se ha realizado. Existen las siguientes diferencias entre asyncio.futures.Future y concurrent.futures.Future -

  • Los métodos result () y exception () no toman un argumento de tiempo de espera y generan una excepción cuando el futuro aún no ha terminado.

  • Las devoluciones de llamada registradas con add_done_callback () siempre se llaman a través de call_soon () del bucle de eventos.

  • La clase asyncio.futures.Future no es compatible con las funciones wait () y as_completed () en el paquete concurrent.futures.

Ejemplo

El siguiente es un ejemplo que le ayudará a entender cómo usar la clase asyncio.futures.future.

import asyncio

async def Myoperation(future):
   await asyncio.sleep(2)
   future.set_result('Future Completed')

loop = asyncio.get_event_loop()
future = asyncio.Future()
asyncio.ensure_future(Myoperation(future))
try:
   loop.run_until_complete(future)
   print(future.result())
finally:
   loop.close()

Salida

Future Completed

Corutinas

El concepto de corrutinas en Asyncio es similar al concepto de objeto Thread estándar en el módulo de subprocesamiento. Ésta es la generalización del concepto de subrutina. Una corrutina se puede suspender durante la ejecución para que espere el procesamiento externo y regrese desde el punto en el que se había detenido cuando se realizó el procesamiento externo. Las siguientes dos formas nos ayudan a implementar corrutinas:

función async def ()

Este es un método para la implementación de corrutinas en el módulo Asyncio. A continuación se muestra un script de Python para el mismo:

import asyncio

async def Myoperation():
   print("First Coroutine")

loop = asyncio.get_event_loop()
try:
   loop.run_until_complete(Myoperation())

finally:
   loop.close()

Salida

First Coroutine

@ asyncio.coroutine decorador

Otro método para la implementación de corrutinas es utilizar generadores con el decorador @ asyncio.coroutine. A continuación se muestra un script de Python para el mismo:

import asyncio

@asyncio.coroutine
def Myoperation():
   print("First Coroutine")

loop = asyncio.get_event_loop()
try:
   loop.run_until_complete(Myoperation())

finally:
   loop.close()

Salida

First Coroutine

Tareas

Esta subclase del módulo Asyncio es responsable de la ejecución de corrutinas dentro de un bucle de eventos de manera paralela. Seguir el script de Python es un ejemplo de procesamiento de algunas tareas en paralelo.

import asyncio
import time
async def Task_ex(n):
   time.sleep(1)
   print("Processing {}".format(n))
async def Generator_task():
   for i in range(10):
      asyncio.ensure_future(Task_ex(i))
   int("Tasks Completed")
   asyncio.sleep(2)

loop = asyncio.get_event_loop()
loop.run_until_complete(Generator_task())
loop.close()

Salida

Tasks Completed
Processing 0
Processing 1
Processing 2
Processing 3
Processing 4
Processing 5
Processing 6
Processing 7
Processing 8
Processing 9

Transportes

El módulo Asyncio proporciona clases de transporte para implementar varios tipos de comunicación. Estas clases no son seguras para subprocesos y siempre se emparejan con una instancia de protocolo después del establecimiento del canal de comunicación.

A continuación se muestran distintos tipos de transportes heredados de BaseTransport:

  • ReadTransport - Esta es una interfaz para transportes de solo lectura.

  • WriteTransport - Esta es una interfaz para transportes de solo escritura.

  • DatagramTransport - Esta es una interfaz para enviar los datos.

  • BaseSubprocessTransport - Similar a la clase BaseTransport.

Los siguientes son cinco métodos distintos de la clase BaseTransport que posteriormente son transitorios en los cuatro tipos de transporte:

  • close() - Cierra el transporte.

  • is_closing() - Este método devolverá verdadero si el transporte se está cerrando o ya está cerrado.

  • get_extra_info(name, default = none) - Esto nos dará información adicional sobre el transporte.

  • get_protocol() - Este método devolverá el protocolo actual.

Protocolos

El módulo Asyncio proporciona clases base que puede subclasificar para implementar sus protocolos de red. Estas clases se utilizan junto con los transportes; el protocolo analiza los datos entrantes y solicita la escritura de los datos salientes, mientras que el transporte es responsable de la E / S real y del almacenamiento en búfer. A continuación se presentan tres clases de protocolo:

  • Protocol - Esta es la clase base para implementar protocolos de transmisión para su uso con transportes TCP y SSL.

  • DatagramProtocol - Esta es la clase base para implementar protocolos de datagramas para su uso con transportes UDP.

  • SubprocessProtocol - Esta es la clase base para implementar protocolos que se comunican con procesos secundarios a través de un conjunto de conductos unidireccionales.