[pyar] Agregar tareas asíncronas por eventos generados de interfaz de usuario

Luis Andraschnik luis.andraschnik en gmail.com
Mie Nov 29 20:07:26 ART 2017


Hola David!

Si yo voy a dar una charla PyAr está en el horno ..Podría titularlo
"Programemos sin saber" ó "Qué bueno que es Python que hasta yo programo"

Aclarando un poco la diferencia de estrategias: Dado que quiero que la
aplicación pueda manejar (leer la temperatura) más de una estufa a la vez y
básicamente la mayor parte del tiempo el programa espera durante el polling
puedo destinar un proceso para cada estufa con un sleep sincrono
(estrategia 1) ó un único hilo con sleep asíncrono (estrategia 2). Las 2
funcionan pero la segunda es menos costosa en términos de recursos (lo
probé haciendo un "top" bajo linux). Ambas estrategias publican en una cola
de mensajes de zmq con el topic que es el número de slave (=estufa) + la
lectura de temperatura y la hora actual

La aplicación completa (cualquiera de las estrategias) tiene un segundo
proceso que subscribe a la cola  y graba en sqlite toda la info para
registro y análisis posterior.

Otro proceso levanta un web server (uso flask), subscribe también a la cola
de mensajes para tener todas las lecturas y vía protocolo server sent event
envía al browser los datos en tiempo real , y mediante plotly.js grafica la
temperatura (live).

Todo lo probé y funciona. ahora necesito controlar via interfaz de usuario
el inicio y final del proceso de leer los datos de cualquier estufa
individualmente sea a través de un schedulling o dando alguna orden directa
via POST/GET , pasando el parámetro slave_number , time_polling,
datos_del_cultivo, temperatura, hora_inicio, hora_fin.

Lo que se me ocurre es hacer una corrutina que cree las tareas, que esté
escuchando en una cola de mensajes atento al topic "inicia" o "parar".

Hice la siguiente prueba que funciona (  no escucha mensajes del exterior)
a modo de simulación

La corrutina gen_tasks() inicia las lecturas de las estufas 1 a 19, con u
polling estandar de 1 segundo entre lecturas, llamando programáticamente a
la corrutina get_temperature() agregando corrutinas a la lista de tareas.
Seguidamente detengo la ejecución de las tareas que corresponden a las
estufas 1 a 9.
Básicamente hay una lista de tareas dónde el índice  0 es gen_tasks , y las
siguientes son las que leen la temperatura de su correspondiente estufa. El
método cancel() hace el trabajo.

Ahora queda ver como iniciar o finalizar tareas desde una interfaz de
usuario.

Acá el nuevo mock en Python >=3.5 (en 3.4 no va a andar)

import asyncio
from datetime import datetime
import numpy as np
import zmq
import random
import sys

port = 4000
context = zmq.Context()
socket = context.socket(zmq.PUB)
socket.bind("tcp://*:%s" % port) # si no tenés nadie que se subscriba no
vas a ver nada

async def gen_tasks():
    '''Realizo un polling preguntando si un usuario ingresó datos para el
inicio o fin
    de un nuevo ensayo'''
    slave=0
    while True:
        slave+=1
        params = slave , 5 #   5 segundos de polling de temperatura para
todas las estufas
        if slave < 20: # inicio las lecturas de estufas 1 a 19
            tasks.append(asyncio.ensure_future(get_temperature(params)))
            if slave==15:
                for i in tasks[1:10]:# detengo las lecturas de estufas 1 a 9
                    print('Cancelling Slave {}'.format(tasks.index(i)))
                    i.cancel()
        await asyncio.sleep(1)# cada segundo pregunto ¿Hay un nuevo ensayo?


async def get_temperature(i):
    slave, poll = i
    while True:
        time = datetime.now()
        temperature = np.random.normal(30,0.5)
        print('Slave: {:0003.0f} Fecha: {: %d-%m-%y %H:%M:%S} Temp:
{:.2f}°C'.format(slave,time,temperature))
        socket.send_string("{:0003.0f},{:s},{:f}".format(slave, time,
temperature))
        await asyncio.sleep(poll)

print("Sending updates from slaves...")

loop = asyncio.get_event_loop()
tasks = [asyncio.ensure_future(gen_tasks())]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()




El 29 de noviembre de 2017, 15:26, David Weil <tenuki en gmail.com> escribió:

> Hola Luis!
>
>
>>
> Que entretenido!
>
> Seguramente se pueden agregar y quitar tareas con asyncio, aunque nunca lo
> hice (es que no use asyncio).
>
> Tampoco me queda en claro las diferencias que comentas en ambas
> estrategías.. si.. una diferencia si.. lo de las tareas x estufa.. pero no
> totalmente que procesos hay que hacen c/u..  si queres contalo un poco
> mejor.
>
> Lo de asyncio seguramente alguien te puede comentar mas!
>
> Hasta luego!!
> dave
> _______________________________________________
> Lista de Correo de PyAr - Python Argentina - pyar en python.org.ar
> Sitio web: http://www.python.org.ar/
>
> Para administrar la lista (o desuscribirse) entrar a
> http://listas.python.org.ar/listinfo/pyar
>
> La lista de PyAr esta Hosteada en USLA - Usuarios de Software Libre de
> Argentina - http://www.usla.org.ar
------------ próxima parte ------------
Se ha borrado un adjunto en formato HTML...
URL: <http://listas.python.org.ar/pipermail/pyar/attachments/20171129/5adf2f5b/attachment.html>


Más información sobre la lista de distribución pyar