[PYTHON] Comment communiquer de manière asynchrone uniquement avec Touch Designer

introduction

TouchDesigner (TD) peut exécuter des scripts python, Si un traitement tel que la communication HTTP prend du temps, il se figera un peu jusqu'à ce que le traitement soit terminé. À ce stade, ** la chronologie de l'ensemble du TD s'arrêtera également et le dessin ne sera pas mis à jour ** Pour éviter cela, nous avons décidé de communiquer de manière asynchrone.

Si vous souhaitez simplement obtenir la valeur de manière asynchrone, vous pouvez utiliser node etc. en plus de TD, mais En raison des circonstances de l'environnement, je voulais le compléter uniquement avec TD, j'ai donc envisagé la méthode suivante.

--Utiliser Web DAT --Utiliser le module threading

Je vais expliquer chacun de ces éléments.

Exemple de code

Cet exemple est téléchargé ci-dessous. https://github.com/genkitoyama/TD_with_asynchronous_communication

Utilisez Web DAT

C'est le plus simple. Avec le paramètre ʻAsynchronous Fetch` activé, Entrez l'URL et appuyez sur le bouton «Récupérer», La chronologie TD ne s'arrête pas et communique dans les coulisses (peut-être curl?). Référence: https://docs.derivative.ca/Web_DAT

Dec-15-2019 14-18-35.gif (Dans l'exemple ci-dessus, API pour trouver l'altitude de l'Institut national de recherche foncière est utilisée.)

Dans le cas de GET, c'est OK si vous le saisissez directement dans l'URL, Dans le cas du POST, c'est OK si vous appuyez sur le bouton «Soumettre» avec le tableau des données que vous voulez envoyer connecté à l'entrée supérieure «Entrée 0». (Au fait, vous pouvez mettre un en-tête HTTP personnalisé dans l'entrée inférieure)

Ensuite, selon le format de l'élément retourné, tirez la valeur requise à l'aide du module XML DAT ou json, et vous avez terminé.

Référence: Analyse JSON en table DAT avec TouchDesigner

Utilisez le module threading

module threading Est un module qui effectue un traitement parallèle multi-thread. Il est inclus en standard dans python3.5 dans TD.

En plaçant la fonction que vous souhaitez exécuter dans un autre thread et l'argument de cette fonction dans l'argument de threading.Thread (), elle sera exécutée dans un autre thread.

Ici, «requests» est utilisé comme module pour la communication HTTP. requests est également inclus en standard dans python dans TD. (Il existe plusieurs autres modules qui effectuent la communication HTTP, mais je pense que vous pouvez utiliser ce que vous voulez.)


import threading
import requests

class HttpRequest():
	def __init__(self):
		self.url = op('URL').text
		self.city_id = op('CITY_ID').text
	
    #Fonctions que vous souhaitez exécuter de manière asynchrone
	def request(self):
		response = requests.get(self.url, params={'city':self.city_id})
		
	def start_request(self):
		myThread = threading.Thread(target=self.request)
		myThread.start()

Ceci est une excellente référence à Article du Dr Matthew Ragan.

Inconvénients et contre-mesures

Le module threading est également très utile, mais il présente quelques inconvénients.

Impossible de détecter la fin du traitement dans un autre thread

Je peux envoyer une commande d'arrêt depuis le thread principal, Il n'est pas possible de détecter lorsque le traitement dans un autre thread est terminé. Si vous utilisez la méthode join (), vous pouvez attendre la fin d'un autre thread, Pendant ce temps, le thread principal s'arrêtera, donc le TD finira par s'arrêter. ..

Par conséquent, il n'est pas facile de faire quelque chose comme "Je frappe l'URL dans un autre thread et exécute ce processus lorsque la valeur est renvoyée".

Impossible de faire référence à l'opérateur TD lors du traitement d'un autre thread

C'est naturel si vous y réfléchissez, mais comme il est en cours de traitement dans un autre thread, Impossible d'accéder à l'opérateur qui réside dans le thread principal du TD.

Par conséquent, il n'est pas possible «d'analyser le résultat renvoyé en frappant l'URL dans un autre thread vers« Table DAT »car il est dans la même fonction».

(Au fait, si vous faites cela, vous obtiendrez un dialogue comme celui-ci) multi_threading_alert.png

Contre-mesures

Donc, c'est tout à fait une compétence, mais j'ai décidé d'utiliser Timer CHOP pour contrôler si la valeur est retournée (≒ si le traitement d'un autre thread est terminé) **.

J'aimerais que vous voyiez l'exemple pour plus de détails, mais en gros, le déroulement est le suivant.

  1. Ecrivez le processus pour stocker la valeur obtenue dans la variable membre de la fonction à exécuter dans un autre thread.
  2. Vérifiez si la variable contient une valeur dans ʻonDone () du callback Timer CHOP`.
  3. Si tel est le cas, le chronomètre s'arrêtera et passera à un autre processus.
  4. Sinon, redémarrez le chronomètre

Dec-15-2019 14-28-46.gif

Dans l'exemple ci-dessus, les [Weather Hacks] de livingoor (http://maps.gsi.go.jp/development/elevation_s.html) sont utilisés. Avec cette API, le résultat sera renvoyé en un instant, donc même si vous le faites de cette façon, ce ne sera pas très délicieux, mais s'il s'agit de l'API d'origine que vous avez utilisée auparavant, il faudra 7 à 8 secondes pour revenir en raison des circonstances. J'ai donc conçu cette méthode.

python a essayé de créer la classe RequestManager et la classe HttpRequest comme suit.


import http_request
import json

class RequestManager():
	def __init__(self):
		self.http = http_request.HttpRequest()
		self.can_start_request = True			#Puis-je faire une demande
		self.max_confirmation_count = 10		#Nombre maximal de confirmations
		self.current_confirmation_count = 0		#Compte de confirmation actuel
		self.timer = op('timer1')
	
	def init_timer(self):
		print('init http request timer')
		
	def start_timer(self):
		#Si vous pouvez faire une demande, lancez une demande, sinon, attendez
		if self.can_start_request == True:
			print('start http request timer')
			self.http.start_request()
		else:
			print('restart timer')
			
	def done_timer(self):
		print('done http request timer')
		#Vérifiez si la valeur est renvoyée
		output = self.http.get_data()
		#S'il n'y a pas de valeur, augmentez le nombre de confirmations et réessayez
		if output is None:
			print('http response is none')
			self.can_start_request = False
			self.current_confirmation_count += 1
			#Lorsque le nombre de confirmations atteint le maximum, il est jugé que la communication a échoué.
			if self.current_confirmation_count >= self.max_confirmation_count:
				print('http out of request')
				self.timer.par.initialize.pulse()
				self.http = http_request.HttpRequest()
				self.current_confirmation_count = 0
			else:
				self.timer.par.start.pulse()
		else:
		#S'il y a une valeur, json est analysé et stocké
			self.can_start_request = True
			out_json = json.loads(output)
			op('out_json')[0,0].val = out_json['forecasts'][0]
			
			self.current_confirmation_count = 0
			self.timer.par.initialize.pulse()

import threading
import requests

class HttpRequest():
	def __init__(self):
		self.url = op('URL').text
		self.city_id = op('CITY_ID').text
		self.out_data = None
		print('http request init')
	
	def request(self):
		get_data = {'city':self.city_id}
		response = requests.get(self.url, params=get_data)
		self.out_data = response.text
		print(self.out_data)
		
	def start_request(self):
		self.out_data = None
		myThread = threading.Thread(target=self.request)
		myThread.start()
		
	def get_data(self):
		return self.out_data

en conclusion

―― Nous avons résumé deux types de méthodes de communication asynchrones en utilisant uniquement TouchDesigner. ――Parce que je suis un débutant en python, je vous serais reconnaissant de bien vouloir commenter la dernière partie de la force brute, surtout si vous avez des idées pour une meilleure méthode ...!

prime

Cette fois, j'ai utilisé TouchPlayer pour exécuter chacun sur plusieurs terminaux, mais comme je ne peux pas voir le Textport avec TouchPlayer, j'ai utilisé la méthode de cracher le journal dans un fichier externe et de le vérifier si une erreur se produisait.

Liens référencés

Recommended Posts

Comment communiquer de manière asynchrone uniquement avec Touch Designer
Comment utiliser Qt Designer
Comment mettre à jour avec SQLAlchemy?
Comment lancer avec Theano
Comment modifier avec SQLAlchemy?
Comment séparer les chaînes avec ','
Comment faire RDP sur Fedora31
Comment supprimer avec SQLAlchemy?
Comment annuler RT avec Tweepy
Python: comment utiliser async avec
Pour utiliser virtualenv avec PowerShell
Comment installer python-pip avec ubuntu20.04LTS
Comment gérer les données déséquilibrées
Comment démarrer avec Scrapy
Comment démarrer avec Python
Comment gérer l'erreur DistributionNotFound
Comment démarrer avec Django
Comment augmenter les données avec PyTorch
Comment calculer la date avec python
Comment installer mysql-connector avec pip3
Comment INNER JOIN avec SQL Alchemy
Comment installer Anaconda avec pyenv
Comment changer le SQLite3 de Django téléchargé sur python n'importe où avec juste une interface graphique
Comment effectuer un traitement arithmétique avec le modèle Django
[Blender] Comment définir shape_key avec un script
Comment titrer plusieurs figures avec matplotlib
Comment obtenir l'identifiant du parent avec sqlalchemy
python à retenir uniquement avec bonjour, mondes
Comment ajouter un package avec PyCharm
Comment installer DLIB avec 2020 / CUDA activé
Comment utiliser ManyToManyField avec l'administrateur de Django
Comment utiliser Cmder avec PyCharm (Windows)
Comment empêcher les mises à jour de paquets avec apt
Comment utiliser BigQuery en Python
Comment utiliser Ass / Alembic avec HtoA
Comment gérer les erreurs de compatibilité d'énumération
Comment utiliser le japonais avec le tracé NLTK
Comment faire un test de sac avec python
Comment rechercher Google Drive dans Google Colaboratory
Comment afficher le japonais python avec lolipop
Comment télécharger des vidéos YouTube avec youtube-dl
Comment utiliser le notebook Jupyter avec ABCI
Comment mettre hors tension de Linux sur Ultra96-V2
Comment utiliser la commande CUT (avec exemple)
Comment entrer le japonais avec les malédictions Python
Comment installer zsh (avec la personnalisation .zshrc)
Comment lire les données de problème avec Paiza
Comment utiliser SQLAlchemy / Connect avec aiomysql
Comment regrouper des volumes avec LVM
Comment installer python3 avec docker centos
Comment utiliser le pilote JDBC avec Redash
Comment supprimer sélectivement les anciens tweets avec Tweepy
Comment télécharger avec Heroku, Flask, Python, Git (4)