Un mundo sin corrutinas. Muletas para el programador - asyncio

1. Introducción



El que ha aprendido a volar ya no gateará. Pero tampoco debe haber arrogancia hacia alguien que, en principio, "no puede volar". Ambos son bastante normales. Ambos son respetados y honorables. Para una persona, esto es como elegir una profesión: usted, convencionalmente, es piloto o conductor. Para los mismos animales, es lo mismo: eres un águila o un lobo, es decir, O vuelas o corres (huyes) Pero solo una persona en sus conceptos, categorías, actitudes y pensamientos dotó a los personajes de características y desarrolló su actitud hacia ellos. Cierto, con matices. Entonces, no, probablemente, es más honorable y romántico que la profesión de piloto, pero ¿tratar de convencer a un camionero o diseñador de aviones de esto? Y aquí es difícil argumentar: ¡hay muchos astronautas incluso ahora, y todavía no hay una segunda reina!



Somos programadores. Quizás en diversos grados, pero algunos, seguro. Con esto quiero decir que somos diferentes y también podemos pensar de diferentes maneras. La afirmación de que un programador solo piensa de manera constante es tan unilateral, dañina e incluso blasfema como el hecho de que una persona solo corre. A veces, y vuela. Algunos, como los pilotos, lo hacen con bastante regularidad, y otros, como los astronautas, incluso durante meses y de forma continua. La idea de un pensamiento coherente disminuye la capacidad humana. En algún momento y por un tiempo, incluso puedes creerlo, pero "todavía gira", se trata del hecho de que tarde o temprano la vida pasará factura.



Asyncio en Python es una muleta de software que imita, en sentido figurado, el vuelo del pensamiento paralelo incorrecto. Una especie de rebote con manos agitadas. A veces parece divertido y torpe. Aunque en una determinada situación esto también es una salida: puedes simplemente cruzar el charco y ensuciarte, pero si la fuerza lo permite, entonces es mejor saltar. ¿Pero quizás a los programadores les falta la fuerza?



Tratemos de descartar las "muletas de software" impuestas y elevarnos por encima de la rutina del software. Y que no sea un salto, o quizás no tan alto y largo, pero aún así, especialmente en comparación con las muletas, un vuelo. Después de todo, una vez Mozhaisky Alexander Fedorovich (que no debe confundirse con el Tribunal Municipal de Mozhaisky de la región de Moscú) o los mismos hermanos Wright superaron varios cientos de metros en el aire por primera vez. Sí, y las pruebas de los aviones modernos comienzan con una carrera y una separación breve de la pista.



2. Un ejemplo muy simple con asyncio



Empezaremos volando en Python. El programa de vuelo es sencillo. Hay aviones (que, sin embargo, en la versión original de las imágenes de arañas, ver [1] ) con los nombres en los fuselajes "Blog", "Noticias", "Foro". Despegan al mismo tiempo. Todos deben enarbolar un segmento del camino en un tiempo determinado y lanzar, digamos, una bandera con el número del segmento cubierto. Esto debe hacerse tres veces. Y solo entonces aterriza.



En Python, un modelo de este comportamiento se describe y luego se simula mediante el código del Listado 1.



Listado 1. Código Python para aviones araña
import asyncio
import time

async def spider(site_name):
 for page in range(1, 4):
     await asyncio.sleep(1)
     print(site_name, page)

spiders = [
 asyncio.ensure_future(spider("Blog")),
 asyncio.ensure_future(spider("News")),
 asyncio.ensure_future(spider("Forum"))
]

start = time.time()

event_loop = asyncio.get_event_loop()
event_loop.run_until_complete(asyncio.gather(*spiders))
event_loop.close()

print("{:.2F}".format(time.time() - start))




Los resultados de la simulación para tal "vuelo" son los siguientes:



Blog 1

Noticias 1

Foro 1

Blog 2

Noticias 2

Foro 2

Blog 3

Noticias 3

Foro 3

3.00



Por qué esto se explica con tanto detalle en el video [1]. Pero nosotros, muchachos con imaginación y el vuelo simultáneo (según el escenario - asincrónico) de nuestros tres "aviones" sin usar asyncio lo presentaremos de una manera diferente - sobre la base de modelos automáticos. Por ejemplo, el Listado 2 muestra el código para un retraso de autómata, un análogo del retraso asíncrono del módulo asyncio, representado por la línea await asyncio.sleep (1) en el Listado 1.



Listado 2. Código de retardo automático en Python
import time

class PSleep:
    def __init__(self, t, p_FSM): self.SetTime = t; self.nState = 0; self.bIfLoop = False; self.p_mainFSM = p_FSM
    def x1(self): return time.time() - self.t0 <= self.SetTime
    def y1(self): self.t0 = time.time()
    def loop(self):
        if (self.nState == 0): self.y1(); self.nState = 1
        elif (self.nState == 1):
            if (not self.x1()): self.nState = 4




El valor de demora y un puntero al objeto que creó el objeto de demora se pasan a través del constructor de la clase. El puntero es requerido por la función de control de proceso, que, después de eliminar el retraso, continuará el proceso principal que se detuvo cuando se creó.



El Listado 3 muestra la contraparte del autómata del plano araña asíncrono (ver también el Listado 1). Es muy probable que un experto en programación de Python no sueñe con esto, ¡incluso en la más pesadilla! ¡El código fuente de cuatro líneas ha crecido 15 veces! ¿No es esto un motivo de admiración por el código Python típico en general y asycio en particular, o al menos una prueba de la ventaja de la "tecnología de rutina" sobre la programación de autómatas?



Listado 3. Código para una araña autómata en Python
# ""   "Blog"
class PBSpider:
    def __init__(self, name):
        self.nState = 0; self.bIfLoop = True; self.site_name = name; self.page = 1;
        self.p_mainFSM = b_sleep;
    def x1(self): return self.page < 4
    def y1(self):
        self.bIfLoop = False; automaton.append(b_sleep);
        b_sleep.p_mainFSM = blog
        automaton[-1].bIfLoop = True;
        automaton[-1].nState = 0
    def y2(self): print(self.site_name, self.page)
    def y3(self): self.page += 1
    def y4(self): self.page = 1
    def loop(self):
        if (self.x1() and self.nState == 0):  self.y1(); self.nState = 1
        elif (not self.x1()  and self.nState == 0): self.y1(); self.y4(); self.nState = 33
        elif (self.nState == 1): self.y2(); self.y3(); self.nState = 0

# ""   "News"
class PNSpider:
    def __init__(self, name):
        self.nState = 0; self.bIfLoop = True; self.site_name = name; self.page = 1;
        self.p_mainFSM = n_sleep;
    def x1(self): return self.page < 4
    def y1(self):
        self.bIfLoop = False; automaton.append(n_sleep);
        n_sleep.p_mainFSM = news
        automaton[-1].bIfLoop = True;
        automaton[-1].nState = 0
    def y2(self): print(self.site_name, self.page)
    def y3(self): self.page += 1
    def y4(self): self.page = 1
    def loop(self):
        if (self.x1() and self.nState == 0):  self.y1(); self.nState = 1
        elif (not self.x1()  and self.nState == 0): self.y1(); self.y4(); self.nState = 33
        elif (self.nState == 1): self.y2(); self.y3(); self.nState = 0

#    "Forum"
class PFSpider:
    def __init__(self, name):
        self.nState = 0; self.bIfLoop = True; self.site_name = name; self.page = 1;
        self.p_mainFSM = f_sleep;
    def x1(self): return self.page < 4
    def y1(self):
        self.bIfLoop = False; automaton.append(f_sleep);
        f_sleep.p_mainFSM = forum
        automaton[-1].bIfLoop = True;
        automaton[-1].nState = 0
    def y2(self): print(self.site_name, self.page)
    def y3(self): self.page += 1
    def y4(self): self.page = 1
    def loop(self):
        if (self.x1() and self.nState == 0):  self.y1(); self.nState = 1
        elif (not self.x1()  and self.nState == 0): self.y1(); self.y4(); self.nState = 33
        elif (self.nState == 1): self.y2(); self.y3(); self.nState = 0

# 
b_sleep = PSleep(1, 0)
n_sleep = PSleep(1, 0)
f_sleep = PSleep(1, 0)
# ""
blog = PBSpider("Blog")
news = PNSpider("News")
forum = PFSpider("Forum")
#    
automaton = []
automaton.append(blog);
automaton.append(news);
automaton.append(forum);
start = time.time()
#   ( event_loop)
while True:
    ind = 0;
    while True:
        while ind < len(automaton):
            if automaton[ind].nState == 4:
                automaton[ind].p_mainFSM.bIfLoop = True
                automaton.pop(ind)
                ind -=1
            elif automaton[ind].bIfLoop:
                automaton[ind].loop()
            elif automaton[ind].nState == 33:
                print("{:.2F}".format(time.time() - start))
                exit()
            ind += 1
        ind = 0




Y aquí está el resultado de vuelos automáticos:



Noticias 1

Foro 1

Blog 1

Blog 2

Noticias 2

Foro 2

Noticias 3

Foro 3

Blog 3

3.00



Pero, hablemos. El aumento en el tamaño del código se debió a problemas con los punteros en Python. Como resultado, tuve que crear una clase para cada página, lo que triplicó el código. Por lo tanto, es más correcto hablar no de 15, sino de cinco veces el volumen. Un "piloto de Python" más hábil en programación podría incluso eliminar esta deficiencia.



Pero la razón principal aún no son los punteros. El código C ++ que se muestra a continuación, con total libertad para trabajar con punteros, tiene aún más líneas por clase. La razón es el modelo computacional utilizado, el lenguaje de su descripción y los enfoques para la implementación de algoritmos basados ​​en él. Figura: 1 muestra un modelo de avión de araña convencional en forma de diagrama de bloques y un modelo de ametralladora. Se nota que exteriormente y en calidad, son modelos diferentes, aunque permiten transformaciones equivalentes. Los autómatas tienen estados, pero los diagramas de bloques ni siquiera tienen rastro de ellos. Los autómatas, por definición, operan en un tiempo discreto, y los diagramas de bloques ni siquiera sueñan con esto. Todo esto impone ciertas obligaciones a la implementación del modelo.



La ausencia del concepto de tiempo discreto es la esencia de los problemas del modelo de programación de diagrama de bloques existente, que debe implementar, estrictamente hablando, irrealizable para él, es decir. procesos paralelos. Recordemos que para los autómatas una red de autómatas, como modelo de procesos paralelos (así como asincrónicos), es su estado natural.



Figura: 1. Modelos automáticos y de diagrama de bloques de un avión araña
image



Pero incluso en el nivel de un proceso separado, los modelos tienen diferencias que se proyectan en el lenguaje y la implementación del modelo. En virtud de estas cualidades, los apologistas de un diagrama de bloques consistente han creado construcciones de lenguaje que, ya sea explícita o implícitamente, hacen posible describirlo de manera muy compacta. Tome el mismo bucle for o al menos una secuencia implícita de ejecución del operador (acciones y1, y2, y3).



Para un diagrama de flujo, puede enumerar las acciones en un cuadro sin ningún problema y esto no cambiará la naturaleza secuencial de su trabajo. Si el autómata reemplaza las transiciones en los estados s2, s3 con un ciclo en el estado s1, marcando el arco con las mismas acciones, entonces el significado del algoritmo cambiará, ya que introducirá paralelismo en su trabajo. Dado que las acciones anteriores deben realizarse estrictamente secuencialmente, esto predeterminó la apariencia del modelo de autómata (ver Fig. 1). Un autómata finito es un modelo que no permite el "doble pensamiento".



La falta de tiempo discreto en los diagramas de bloques fue su ventaja. Pero ahora esto se ha convertido en su principal desventaja. Afecta, como puede no parecer una blasfemia, y la forma de pensar. Los lenguajes secuenciales justifican el pensamiento secuencial de los programadores negándoles algo más: el paralelo. Esto es lo que justifica las construcciones de la programación asincrónica existente, presentando el conjunto y funcionalidad de los operadores del mismo paquete asyncio. Y es precisamente este enfoque, se argumenta, el que permite a los programadores familiarizados con programas secuenciales convertirse en asincrónicos (casi paralelos).



Pero volvamos al tema del artículo y sus imágenes. ¡Queríamos nuestro "avión" y lo conseguimos! Los vuelos, o más precisamente, sus resultados visibles, son algo diferentes en apariencia, pero completamente indistinguibles por naturaleza. Se pueden interpretar de tal manera que las banderas se seleccionaron y registraron en el protocolo en un orden diferente, pero los "aviones" volaron como debían, es decir, simultáneamente y simultáneamente arrojaron sus banderas. Y en qué orden se registraron, el caso, como dicen, es el décimo. Lo principal se realiza y se cumple: la secuencia y los tiempos de su lanzamiento corresponden al programa de vuelo.



El código se puede acortar. Entonces, aparentemente, puede limitarse al código de una sola clase. También puede ocultar el código de bucle de eventos. Si, al mismo tiempo, en el código fuente, abre el código del compartimiento del motor, que está oculto detrás del asyncio y espera a los operadores, entonces el volumen del código del autómata probablemente no será tan aterrador.



3. Sobre los problemas de implementar autómatas en Python



Detengámonos con más detalle en los problemas que dieron lugar a la aparición del código automático. Lo último que se esconde allí parece hasta ahora monstruoso en comparación con el código fuente. Pero observemos que el primer avión de Mozhaisky estaba lejos de ser similar al moderno "secado", y los primeros autos no se diferenciaron para mejor de ninguno de sus contrapartes modernas. Permítanme enfatizar que los problemas del código autómata presentado están relacionados en gran medida con mi comprensión actual del lenguaje Python y, posiblemente, en menor medida con las capacidades del lenguaje mismo.



Sin embargo, el primer problema está relacionado con el lenguaje de descripción del modelo de autómata. En C ++ se resuelve mediante el lenguaje. No veo tales posibilidades en Python. Desafortunadamente, como a veces dicen ahora, de la palabra en absoluto. Por tanto, se tomó como base el método de implementación de autómatas basado en operadores de control del lenguaje if-elif-else. Además, recordamos que en el CPSU (a), además de los propios autómatas, se introdujeron la memoria de sombra y los espacios de autómatas para implementar plenamente el paralelismo. Sin esto, las posibilidades de la programación de autómatas son muy limitadas y en muchos sentidos inferiores.



El siguiente problema que ya mencionamos son los punteros. No hay problemas con ellos en C ++. En el marco del CPSU (a), de acuerdo con el paradigma OOP, se creó una clase de autómata básica, a partir de la cual se generan clases de autómata aplicadas, y sus parámetros pueden ser no solo punteros, sino incluso sus direcciones. Todo esto hace posible describir e implementar de manera simple, compacta y muy eficiente cualquier tarea que incluya muchos procesos de interacción paralela.



El siguiente es el código de las clases de autómatas de C ++ equivalente al ejemplo considerado. El código de retardo en el Listado 4 es equivalente a la línea await asyncio.sleep (1) en el Listado 1. En forma gráfica, corresponde al modelo de autómata FAwaitSleep de la Figura 1. 1. Tal y sólo tal autómata puede considerarse asincrónico y no ralentizará el flujo computacional. FSleep en la misma figura corresponde al operador habitual sleep (). Es más simple, pero está garantizado que destruirá el modelo de tiempo discreto debido a la acción de y1 que causa el retraso secuencial habitual. Y esto ya no sirve para nada.



Listado 4. Código de retardo asincrónico
//  (  )
#include "lfsaappl.h"
#include <QTime>

class FAwaitSleep :
    public LFsaAppl
{
public:
    FAwaitSleep(int n);
protected:
    int x1();
    QTime time;
    int nAwaitSleep;
};

#include "stdafx.h"
#include "FAwaitSleep.h"

static LArc TBL_AwaitSleep[] = {
    LArc("s1",		"s1","x1",  "--"),			//
    LArc("s1",		"00","^x1",	"--"),			//
    LArc()
};

FAwaitSleep::FAwaitSleep(int n):
    LFsaAppl(TBL_AwaitSleep, "FAwaitSleep")
{
    nAwaitSleep = n; time.start();
}

int FAwaitSleep::x1() { return time.elapsed() < nAwaitSleep; }




El código C ++ para el plano de araña se muestra en el Listado 5. Este código es mucho más adecuado para su modelo que el diagrama de bloques del código Python. Especialmente si comparamos la tabla de transición del autómata y la apariencia del gráfico del autómata. Son simplemente diferentes formas de describir el mismo concepto abstracto: un autómata. También muestra cómo se pasa un puntero a la clase principal al crear un retraso (ver la llamada al método FCall en la actividad y1)



Listado 5. Código para un avión araña que simula la lectura de páginas del sitio
// "".   
#include "lfsaappl.h"

class FAwaitSleep;
class FSpider :
    public LFsaAppl
{
public:
    LFsaAppl* Create(CVarFSA *pCVF) { Q_UNUSED(pCVF)return new FSpider(nameFsa); }
    bool FCreationOfLinksForVariables() override;
    FSpider(string strNam);
    virtual ~FSpider(void);
    CVar *pVarStrSiteName;		//  
    FAwaitSleep *pFAwaitSleep{nullptr};
protected:
    int x1(); void y1(); void y2(); void y3(); void y4();
    int page{1};
};

#include "stdafx.h"
#include "FSpider.h"
#include "FSleep.h"
#include "FAwaitSleep.h"
#include <QDebug>

static LArc TBL_Spider[] = {
    LArc("st","s1","--","--"),		
    LArc("s1","s2","x1","y1"),  // x1- <. ; y1-;
    LArc("s2","s3","--","y2"),  // y2-   ;
    LArc("s3","s1","--","y3"),  // y3-   
    LArc("s1","st","^x1","y4"), // y4-   
    LArc()
};
FSpider::FSpider(string strNam):
    LFsaAppl(TBL_Spider, strNam)
{ }
FSpider::~FSpider(void) { if (pFAwaitSleep) delete pFAwaitSleep; }

bool FSpider::FCreationOfLinksForVariables() {
    pVarStrSiteName = CreateLocVar("strSiteName", CLocVar::vtString, "name of site");
    return true;
}
//      ?
int FSpider::x1() { return page < 4; }
// create delay - pure sleep (synchronous function) or await sleep (asynchronous function)
void FSpider::y1() {
    //sleep(1000);
    // await sleep (asynchronous function)
    if (pFAwaitSleep) delete pFAwaitSleep;
    pFAwaitSleep = new FAwaitSleep(1000);
    pFAwaitSleep->FCall(this);
}
void FSpider::y2() {
#ifdef QT_DEBUG
    string str = pVarStrSiteName->strGetDataSrc();
    printf("%s%d", str.c_str(), page);
    qDebug()<<str.c_str()<<page;
#endif
}
void FSpider::y3() { page++; }
void FSpider::y4() { page = 1; }




No existe ningún código que implemente las funciones del llamado bucle de eventos. Simplemente no es necesario. sus funciones son realizadas por el núcleo del entorno CPSU (a). Crea objetos y gestiona su ejecución paralela en tiempo discreto.



4. Conclusiones



La brevedad no siempre es hermana del talento y, a veces, también es un signo de falta de lengua. Es cierto que es difícil distinguir uno de otro a la vez. El código Python a menudo será más corto que el código C ++. Pero esto es típico de casos simples. Cuanto más compleja sea la solución, menor será esta diferencia. Al final, incluso la complejidad de la solución está determinada por las capacidades del modelo. Un modelo de autómata es mucho más poderoso que un diagrama de bloques.



Los autómatas y la paralelización son, ante todo, medios muy eficaces para resolver problemas de complejidad, combatirlos, y no tanto un medio para aumentar la velocidad de un programa. Dado que todo esto es un modelo de autómata, el paralelismo es difícil de implementar en Python, entonces, a pesar de todos sus chips, baterías y mucho más, es difícil para mí influir en su dirección. Prestaría más atención al entorno C ++, y la introducción no muy justificada de las mismas corrutinas en él. Este modelo es temporal y el motivo de su implementación es en gran parte forzado. ¿Qué vamos a hacer con esta "muleta" cuando se solucione el problema de elegir un modelo paralelo?



Por lo tanto, lo siento, pero mi preferencia sigue estando en el lado de C ++. Y si considera el área de mis intereses profesionales: los sistemas industriales del llamado "espeluznante" en tiempo real duro, entonces no tengo otra opción como tal. Sí, se puede crear algún tipo de entorno, algún tipo de servicio usando Python. Es conveniente, es rápido, hay muchos prototipos, etc. etc. Pero el núcleo de la solución, su modelo paralelo, la lógica de los procesos mismos son inequívocamente C ++, inequívocamente autómatas. Aquí los autómatas, por supuesto, son más importantes y gobiernan. Pero no corrutinas :)



Además ... Mira el video [2] , prestando atención a la implementación del modelo de cohete. Sobre ella, a partir de aproximadamente el minuto 12, narra el video. Respeto al profesor por el uso de las máquinas :) Y para un dulce capricho, otra solución de [3]... Está en el espíritu de la programación asincrónica y asyncio. En realidad, todo comenzó con este ejemplo: la implementación de autómatas anidados en Python. Aquí, la profundidad de anidación es incluso mayor que en el ejemplo detallado anteriormente. El Listado 6 muestra el código fuente y su contraparte Python autómata. En la Fig. 2 es el modelo automático para beber té y el Listado 7 muestra la implementación de C ++ equivalente para VKP (a). Comparar, analizar, sacar conclusiones, criticar ...



Listado 6. Leer y beber té de forma asincrónica en Python
import asyncio
import time

# # Easy Python. Asyncio  python 3.7 https://www.youtube.com/watch?v=PaY-hiuE5iE
# # 10:10
# async def teatime():
#     await asyncio.sleep(1)
#     print('take a cap of tea')
#     await asyncio.sleep(1)
#
# async def read():
#     print('Reading for 1 hour...')
#     await teatime()
#     print('...reading for 1 hour...')
#
# if __name__ == '__main__':
#     asyncio.run(read())

class PSleep:
    def __init__(self, t, p_FSM): self.SetTime = t; self.nState = 0; self.bIfLoop = False; self.p_mainFSM = p_FSM
    def x1(self): return time.time() - self.t0 <= self.SetTime
    def y1(self): self.t0 = time.time()
    def loop(self):
        if (self.nState == 0): self.y1(); self.nState = 1
        elif (self.nState == 1):
            if (not self.x1()): self.nState = 4

class PTeaTime:
    def __init__(self, p_FSM): self.nState = 0; self.bIfLoop = False; self.p_mainFSM = p_FSM;
    def y1(self): self.bIfLoop = False; automaton.append(sl); automaton[-1].bIfLoop = True; automaton[-1].nState = 0
    def y2(self): print('take a cap of tea')
    def loop(self):
        if (self.nState == 0):  self.y1(); self.nState = 1
        elif (self.nState == 1): self.y2(); self.nState = 2
        elif (self.nState == 2): self.y1(); self.nState = 3
        elif (self.nState == 3): self.nState = 4

class PRead:
    def __init__(self): self.nState = 0; self.bIfLoop = False;
    def y1(self): print('Reading for 1 hour...')
    def y2(self): self.bIfLoop = False; automaton.append(rt); automaton[-1].bIfLoop = True; automaton[-1].nState = 0
    def loop(self):
        if (self.nState == 0): self.y1(); self.nState = 1
        elif (self.nState == 1): self.y2(); self.nState = 2
        elif (self.nState == 2): self.y1(); self.nState = 33; self.bIfLoop = False

read = PRead()
rt = PTeaTime(read)
sl = PSleep(5, rt)
automaton = []
automaton.append(read); automaton[-1].bIfLoop = True
while True:
    ind = 0;
    while True:
        while ind < len(automaton):
            if automaton[ind].nState == 4:
                automaton[ind].p_mainFSM.bIfLoop = True
                automaton.pop(ind)
                ind -=1
            elif automaton[ind].bIfLoop:
                automaton[ind].loop()
            elif automaton[ind].nState == 33:
                exit()
            ind += 1
        ind = 0




Figura: 2. Modelo automático de beber té
image



Listado 7. Leer y beber té de forma asincrónica en C ++
#include "lfsaappl.h"

class FRead :
    public LFsaAppl
{
public:
    LFsaAppl* Create(CVarFSA *pCVF) { Q_UNUSED(pCVF)return new FRead(nameFsa); }
    FRead(string strNam);
    virtual ~FRead(void);
protected:
    void y1(); void y2();  void y3();
    LFsaAppl *pFRealTime{nullptr};
};

#include "stdafx.h"
#include "FRead.h"
#include "FTeaTime.h"
#include <QDebug>

static LArc TBL_Read[] = {
    LArc("s1","s2","--","y1"),	// Reading for 1 hour...
    LArc("s2","s3","--","y2"),	// Call(TeaTime)
    LArc("s3","s4","--","y1"),	// Reading for 1 hour...
    LArc("s4","s5","--","y3"),	// sleep(5)
    LArc("s5","s1","--","--"),	//
    LArc()
};
FRead::FRead(string strNam):
    LFsaAppl(TBL_Read, strNam)
{ }
FRead::~FRead(void) { if (pFRealTime) delete pFRealTime; }

void FRead::y1() {
#ifdef QT_DEBUG
    qDebug()<<"Reading for 1 hour...";
#endif
}
void FRead::y2() {
    if (pFRealTime) delete pFRealTime;
    pFRealTime = new FTeaTime("TeaTime");
    pFRealTime->FCall(this);
}
void FRead::y3() { FCreateDelay(5000); }


#include "lfsaappl.h"

class FTeaTime :
    public LFsaAppl
{
public:
    FTeaTime(string strNam);
protected:
    void y1(); void y2();
};
#include "stdafx.h"
#include "FTeaTime.h"
#include <QDebug>
#include "./LSYSLIB/FDelay.h"

static LArc TBL_TeaTime[] = {
    LArc("s1",	"s2","--","y1"),// sleep(1)
    LArc("s2",	"s3","--","y2"),// take a cap of tea
    LArc("s3",	"s4","--","y1"),// sleep(1)
    LArc("s4",	"00","--","--"),//
    LArc()
};

FTeaTime::FTeaTime(string strNam):
    LFsaAppl(TBL_TeaTime, strNam)
{ }

void FTeaTime::y1() { FCreateDelay(2000); }
void FTeaTime::y2() {
#ifdef QT_DEBUG
    qDebug()<<"take a cap of tea";
#endif
}




PD



Ya después de escribir el artículo, después de leer la traducción del artículo de Yerain Díaz [4] , me familiaricé con otra mirada bastante interesante y bastante admiradora sobre las corrutinas en general y asyncio en particular. A pesar de este hecho y de otros similares, seguiremos "yendo por el otro lado" :) Estoy de acuerdo sólo en una cosa con Rob Pike, que "la concurrencia no es un paralelo". La competitividad, se podría decir incluso más dura, no tiene nada que ver con el paralelismo. Y es notable que Google Translate traduzca esta frase como "El paralelismo no es el paralelismo". El hombre llamado Google ciertamente está equivocado. ¿Pero alguien lo convenció de esto? :)



Literatura



  1. Shultais Education. 1. . [ ], : www.youtube.com/watch?v=BmOjeVM0w1U&list=PLJcqk6mrJtxCo_KqHV2rM2_a3Z8qoE5Gk, . . . ( 01.08.2020).
  2. Computer Science Center. 9. async / await ( Python). [ ], : www.youtube.com/watch?v=x6JZmBK2I8Y, . . . ( 13.07.2020).
  3. Easy Python. Asyncio python 3.7. [ ], : www.youtube.com/watch?v=PaY-hiuE5iE, . . . ( 01.08.2020).
  4. Yeray Díaz. Asyncio para el desarrollador de Python en ejercicio. [Recurso electrónico], modo de acceso: www.youtube.com/watch?v=PaY-hiuE5iE , gratis. Idioma. ruso (fecha de tratamiento 08/01/2020).



All Articles