J'écris une application qui écoute les événements sonores (en utilisant les messages transmis avec Open Sound Control), puis en fonction de ces événements suspend ou reprend l'exécution du programme. Ma structure fonctionne la plupart du temps mais bombarde toujours la boucle principale, donc je suppose que c'est un problème de thread. Voici une version générique, simplifiée de ce dont je parle:question de structure de threads idéale (implique plusieurs communications de thread)
import time, threading
class Loop():
aborted = False
def __init__(self):
message = threading.Thread(target=self.message, args=((0),))
message.start()
loop = threading.Thread(target=self.loop)
loop.start()
def message(self,val):
if val > 1:
if not self.aborted:
self.aborted = True
# do some socket communication
else:
self.aborted = False
# do some socket communication
def loop(self):
cnt = 0
while True:
print cnt
if self.aborted:
while self.aborted:
print "waiting"
time.sleep(.1);
cnt += 1
class FakeListener():
def __init__(self,loop):
self.loop = loop
listener = threading.Thread(target=self.listener)
listener.start()
def listener(self):
while True:
loop.message(2)
time.sleep(1)
if __name__ == '__main__':
loop = Loop()
#fake listener standing in for the real OSC event listener
listener = FakeListener(loop)
Bien sûr, ce code simple semble fonctionner à merveille, il est donc clair illustrant pas complètement mon code réel, mais vous voyez l'idée. Ce qui n'est pas inclus ici, c'est aussi le fait que sur chaque boucle, la pause et la reprise (en définissant aborted = True/False) aboutissent à une communication par socket qui implique également des threads.
Ce qui se passe toujours dans mon code, c'est que la boucle principale ne reprend pas toujours là où elle s'était arrêtée après un événement sonore. Cela fonctionnera pour un certain nombre d'événements, mais finalement, il ne répondra tout simplement pas.
Des suggestions pour structurer ce type de communication entre threads?
MISE À JOUR:
ok, je pense que je l'ai. voici une modification qui semble fonctionner. un thread d'écoute met périodiquement une valeur dans un objet File d'attente. il y a un thread checker qui continue de vérifier la file d'attente à la recherche de la valeur, et une fois qu'il l'a vu, il place un booléen dans son état opposé. cette valeur booléenne contrôle si le thread de boucle continue ou attend.
Je ne suis pas entièrement sûr de ce que fait la fonction q.task_done() ici.
import time, threading
import Queue
q = Queue.Queue(maxsize = 0)
class Loop():
aborted = False
def __init__(self):
checker = threading.Thread(target=self.checker)
checker.setDaemon(True)
checker.start()
loop = threading.Thread(target=self.loop)
loop.start()
def checker(self):
while True:
if q.get() == 2:
q.task_done()
if not self.aborted:
self.aborted = True
else:
self.aborted = False
def loop(self):
cnt = 0
while cnt < 40:
if self.aborted:
while self.aborted:
print "waiting"
time.sleep(.1)
print cnt
cnt += 1
time.sleep(.1)
class fakeListener():
def __init__(self):
listener = threading.Thread(target=self.listener)
listener.setDaemon(True)
listener.start()
def listener(self):
while True:
q.put(2)
time.sleep(1)
if __name__ == '__main__':
#fake listener standing in for the real OSC event listener
listener = fakeListener()
loop = Loop()
Voici votre exemple réécrit pour utiliser le multiprocessing http://codepad.org/IRz04lkH – jfs
Quel est l'avantage de la librairie multiproc over threading? Je cours généralement sur un mac avec un i5 donc avoir plusieurs cœurs pour travailler avec. mais si cela se passe sur une machine sans plusieurs cœurs, est-ce simplement une implémentation par défaut? – mix
Pour l'exemple trivial, peu importe, cela dépend de ce que fait votre vrai programme. Python a GIL qui sérialise l'accès à la plupart des parties de l'interpréteur. Mindblowing Python GIL http://blip.tv/file/2232410 – jfs