Cet article est l'article du 22ème jour de "DSL Advent Calendar 2019".
Noël, le réveillon du nouvel an, le nouvel an et les grands événements arrivent bientôt. Il semble que ce soit la saison où elle devient dynamique et moins chargée. Comment allez-vous? À la fin du calendrier de l'Avent, le fait qu'il soit tourné par un petit nombre de personnes est juste avant l'effondrement mental, Le joueur solo qui continue d'écrire jusqu'à aujourd'hui est sur le point de sortir des humains.
Les membres de cette ad-care sont liés au DSL, mais je participerai au cadre OB! Je suis diplômé d'une école de premier cycle et je suis ingénieur dans une certaine entreprise informatique. Je voudrais résumer et présenter ce que j'ai étudié pendant environ six mois depuis mon arrivée dans l'entreprise.
Désormais, pour effectuer un apprentissage automatique sur le Web, vous devez être conscient des points suivants.
Pour traiter ce point, il est multi-processus et il est possible de gérer le traitement de début et de fin de chaque processus. Programmez le système. ~~ C'est ennuyeux. ~~
Le premier est le monument non bloquant IO async / await. Si vous avez touché le frontal, vous pouvez bien entendu l'utiliser. En fait, c'est aussi en Python.
Cependant, contrairement à async / await de javascript, les fonctions async ont toujours un objet collout. Il retourne, donc il ne peut être exécuté que dans une boucle d'événements.
Il existe un concept appelé système de systèmes en tant que méthode concrète de conception d'un système. À l'origine pas dans la conception de logiciels mais dans d'autres domaines tels que les processus métier Est-ce comme quelque chose utilisé? Mais cette fois, je vais mettre cela dans la partie gestion des processus.
Un système se compose de 0 ou plusieurs systèmes. À ce stade, le système enfant est appelé un sous-système par rapport au système parent. Lorsque tous les sous-systèmes ont été démarrés, le système parent est traité comme "démarré". Lorsque tous les sous-systèmes sont terminés, le système parent est traité comme «fermé».
Le système prend les états indiqués dans le tableau ci-dessous. Les états qui peuvent être passés de chaque état sont fixes, et il n'est pas possible de passer soudainement de l'état initial à l'exécution, etc.
Statut | La description | La transition est possible |
---|---|---|
initial | L'état donné comme valeur initiale immédiatement après la création du système | ready, disabled |
ready | Un état qui indique que le système est prêt à fonctionner | running |
running | État lorsque le système fonctionne | completed, intermitted, terminated |
completed | Un état indiquant que le système a terminé l'exécution normalement | - |
disabled | Vous pouvez passer à prêt en supprimant l'état qui indique que le système ne peut pas être exécuté et la cause de l'inexécutabilité. | ready |
intermitted | Un état qui indique que le système est en panne, vous pouvez faire des allers-retours entre les interférences et l'exécution autant de fois que vous le souhaitez pendant que le système fonctionne.(C'est difficile de faire comme ça) | running |
terminated | Contrairement à l'état où le système a été interrompu de force, désactivé, il n'est pas possible de passer à partir d'ici | - |
La figure ci-dessous est un simple diagramme de transition d'état. Si le processus se déroule normalement sans aucune erreur en cours de route, il prendra la route bleue. Si le processus ne peut pas se poursuivre en raison d'une situation inattendue, il sera désactivé ou terminé par la route rouge. En outre, la transition de la voie verte est essentiellement lancée par le jugement et le fonctionnement humain.
Dans la section précédente, nous avons présenté chaque état du système et l'avons défini. Ensuite, nous définirons la transition d'état, ou la flèche dans la figure. La définition est un peu têtue, mais assurez-vous de la garder solide pour ne pas avoir à vous inquiéter lors de l'écriture d'un programme. J'ai préparé un tableau et une figure comme avant.
transition | La description |
---|---|
activate(Activation) | Exécuter la fonction de préparation qui collecte les matériaux nécessaires à l'exécution |
disable(Annulation) | Modifiez la valeur de la variable qui stocke l'état sur désactivé |
enable(Activation) | Modifiez la valeur de la variable qui stocke l'état sur prêt |
start(début) | Exécuter la fonction principale qui effectue des traitements lourds tels que l'apprentissage automatique et la boucle infinie |
complete(Terminé) | Exécutez la fonction d'arrêt pour libérer de la mémoire, etc. |
suspend(Suspension) | 実行中のmain関数にSuspensionシグナルを送ります |
resume(Reprendre) | 中断中のmain関数にReprendreシグナルを送ります |
terminate(résiliation forcée) | Exécutez la fonction de démontage pour libérer de la mémoire, etc. |
De nouveaux mots tels que la fonction de préparation et la fonction principale sont sortis, Ces derniers faciliteront l'écriture de programmes.
Comme image concrète, lors de la création de chaque système en héritant de la classe System d'origine, Vous devez insérer super () chaque fois que vous remplacez activer ou démarrer. (Parce que le changement d'état et la journalisation sont effectués à chaque transition) Ceci est ennuyeux, vous pouvez donc le résoudre en laissant chaque processus spécifique au système s'échapper vers une autre fonction telle que prepare ou main.
Bien que le titre mentionne l'apprentissage automatique, dans un souci de simplicité, nous substituerons cette fois la fonction de veille à un processus chronophage. Tout d'abord, créez la classe System d'origine.
class System():
def __init__(self, name):
self.name = name
self.state = "initial"
self.kwargs = {}
self.log(self.state)
def log(self, msg):
date = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")
line = f"{date}\t[{self.name}]\tpid:{os.getpid():05d}\t{msg}"
print(line)
def prepare(self, **kwargs):
pass
def main(self):
pass
def activate(self):
self.prepare(**self.kwargs)
self.state = "ready"
self.log(self.state)
def start(self):
self.state = "running"
self.log(self.state)
self.main()
def complete(self):
self.state = "completed"
self.log(self.state)
def transit(self):
self.activate()
self.start()
self.complete()
async def run(self, **kwargs):
self.kwargs = kwargs
executor = ProcessPoolExecutor(max_workers=None)
loop = asyncio.get_event_loop()
await loop.run_in_executor(executor, self.transit)
Il ne fonctionne que sleep en parallèle, donc il n'implémente pas tous les états et transitions introduits à l'infini: sob :: pri:
Le constructeur \ _ \ _ init \ _ \ _ nomme ce système et définit l'état initial. En transit, la transition de l'itinéraire bleu est exécutée dans l'ordre. Lors de la mise en œuvre de la désactivation ou de l'arrêt Je pense que vous pouvez écrire magnifiquement si vous mettez try - sauf dans cette partie.
Dans la dernière exécution définie comme la fonction async, run_in_executor permet au transit d'être traité comme une fonction collout. De plus, dans prepare etc., il peut prendre un argument en fonction de l'utilisateur, donc comme argument de longueur variable Je voudrais le passer en transit et même actif, mais dans le cas de ce run_inexecutor, multi-processus J'obtiens une erreur lorsque j'essaye de transmettre un argument de longueur variable. Puisqu'il n'y a aucun moyen, il est stocké dans la variable d'instance kwargs.
Ensuite, créez un système qui exécute le «système qui exécute la fonction de veille». C'est une phrase déroutante, mais si vous voulez exécuter plusieurs systèmes, Je veux éviter d'écrire directement dans \ _ \ _ main \ _ \ _, donc je vais créer un appSystem comme un système d'enroulement.
class appSystem(System):
def prepare(self):
pass
def main(self):
sleep1 = sleepSystem("sleepSystem1")
sleep2 = sleepSystem("sleepSystem2")
systems = asyncio.gather(
sleep1.run(sleep=5),
sleep2.run(sleep=3)
)
loop = asyncio.get_event_loop()
loop.run_until_complete(systems)
Ici, la signification de séparer les processus tels que l'activation et la préparation, et le démarrage et le principal ressort. Cette fois, c'est juste dormir, donc il n'y a rien de spécial à écrire pour préparer. ~~ Vous pouvez forcer l'écriture des variables stockées dans l'instance ... ~~
Exécutez sleepSystem1 qui dort pendant 5 secondes et sleepSystem2 qui dort pendant 3 secondes dans main. sleepSystem est un système simple comme celui-ci:
class sleepSystem(System):
def prepare(self, sleep=3):
self.sleep = sleep
def main(self):
time.sleep(self.sleep)
Après cela, ajoutez appSystem.run () à la boucle d'événements avec la fonction principale. 13
def main():
app = appSystem("appSystem")
loop = asyncio.get_event_loop()
loop.run_until_complete(app.run())
if __name__ == "__main__":
main()
Lançons-le.
2019-12-14 16:43:28.843830 [appSystem] pid:30360 initial
2019-12-14 16:43:29.196505 [appSystem] pid:21020 ready
2019-12-14 16:43:29.196505 [appSystem] pid:21020 running
2019-12-14 16:43:29.197501 [sleepSystem1] pid:21020 initial
2019-12-14 16:43:29.197501 [sleepSystem2] pid:21020 initial
2019-12-14 16:43:29.799470 [sleepSystem1] pid:29720 ready
2019-12-14 16:43:29.803496 [sleepSystem1] pid:29720 running
2019-12-14 16:43:29.872484 [sleepSystem2] pid:18868 ready
2019-12-14 16:43:29.872484 [sleepSystem2] pid:18868 running
2019-12-14 16:43:32.873678 [sleepSystem2] pid:18868 completed
2019-12-14 16:43:34.804446 [sleepSystem1] pid:29720 completed
2019-12-14 16:43:34.804446 [appSystem] pid:21020 completed
De gauche à droite, la date, le nom du système, le PID et l'état. Les heures auxquelles sleepSystem1 et sleepSystem2 sont entrés en état de fonctionnement sont presque identiques, De plus, ce sont des processus séparés et se déroulent en même temps, et après 3 à 5 secondes, la transition d'état terminée, Et vous pouvez voir l'appSystem terminé.
Enfin, je posterai l'intégralité du programme.
import asyncio
import time
from datetime import datetime
import os
from concurrent.futures import ProcessPoolExecutor
class System():
def __init__(self, name):
self.name = name
self.state = "initial"
self.kwargs = {}
self.log(self.state)
def log(self, msg):
date = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")
line = f"{date}\t[{self.name}]\tpid:{os.getpid():05d}\t{msg}"
print(line)
def prepare(self, **kwargs):
pass
def main(self):
pass
def activate(self):
self.prepare(**self.kwargs)
self.state = "ready"
self.log(self.state)
def start(self):
self.state = "running"
self.log(self.state)
self.main()
def complete(self):
self.state = "completed"
self.log(self.state)
def transit(self):
self.activate()
self.start()
self.complete()
async def run(self, **kwargs):
self.kwargs = kwargs
executor = ProcessPoolExecutor(max_workers=None)
loop = asyncio.get_event_loop()
await loop.run_in_executor(executor, self.transit)
class appSystem(System):
def prepare(self):
pass
def main(self):
sleep1 = sleepSystem("sleepSystem1")
sleep2 = sleepSystem("sleepSystem2")
systems = asyncio.gather(
sleep1.run(sleep=5),
sleep2.run(sleep=3)
)
loop = asyncio.get_event_loop()
loop.run_until_complete(systems)
class sleepSystem(System):
def prepare(self, sleep=3):
self.sleep = sleep
def main(self):
time.sleep(self.sleep)
def main():
app = appSystem("appSystem")
loop = asyncio.get_event_loop()
loop.run_until_complete(app.run())
if __name__ == "__main__":
main()
Bien que ce fût une précipitation, j'ai présenté un exemple de conception d'application Web pour l'apprentissage automatique. L'exemple de programme est uniquement en veille, mais il n'implémente pas le serveur www ou l'apprentissage automatique. Puisque l'idée elle-même est la même, je pense qu'il y a peu de temps et d'efforts. (~~ Si vous écrivez trop concrètement, c'est une chose semblable à une entreprise, donc c'est considérablement simplifié ~~)
De plus, la communication entre les systèmes s'effectue à l'aide du WebSocket de base. C'est une bonne idée de créer un websocketSystem séparé du wwwSystem et d'en faire un sous-système de l'appSystem.
Alors comment c'était? Je ne l'ai pas encore utilisé depuis longtemps, mais je l'aime personnellement à cause de son beau design.
http://itdoc.hitachi.co.jp/manuals/3020/30203M8120/EM810359.HTM
Recommended Posts