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.
Cet exemple est téléchargé ci-dessous. https://github.com/genkitoyama/TD_with_asynchronous_communication
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
(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
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.
Le module threading
est également très utile, mais il présente quelques inconvénients.
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".
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)
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.
du callback
Timer CHOP`.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
―― 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 ...!
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.
Recommended Posts