Je fais un projet impliquant la collecte de données et la journalisation. J'ai 2 threads en cours d'exécution, un fil de collection et un thread de journalisation, les deux ont commencé à la main. J'essaie de permettre au programme d'être résilié gracieusement lorsque CTRL-C.
J'utilise un Le second Je ne comprends pas pourquoi le deuxième fil ne se termine jamais. Je basse ce que j'ai fait sur cette réponse: Arrêt d'un fil après une certaine quantité de temps a>. Qu'est-ce que je manque? P> filetage.event code> pour signaler aux fils pour mettre fin à leurs boucles respectives. Cela fonctionne bien pour arrêter la méthode sim_collectdata code>, mais il ne semble pas être correctement arrêter le fil code> logData code>. La collection Collection Terminé code> L'instruction d'impression n'est jamais exécutée et que le programme vient de stalle. (Ça ne se termine pas, il suffit de rester là). P> tandis que code> boucle dans logData code> est de vous assurer que tout dans la file d'attente est enregistré. L'objectif est que CTRL-C arrête immédiatement le fil de collection, puis permettez au fil de journalisation de terminer la vidange de la file d'attente et de terminer uniquement complètement le programme. (En ce moment, les données sont simplement imprimées - finalement, il va être enregistré dans une base de données). P>
4 Réponses :
Vous appelez un blocage Obtenez sur votre Pour correction, vous voudrez appeler Voici ma suggestion: P> INPUT_QUEUE CODE> sans délai. Dans l'une ou l'autre section de logData code>, si vous appelez input_queue.get () code> et la file d'attente est vide, elle bloquera indéfiniment, empêchant le Logging_thread code> Atteindre l'achèvement. INPUT_QUEUE.GET_NOWAIT () code> ou transmettre un délai d'attente sur INPUT_QUEUE.get () code>. p> try:
while True:
time.sleep(10)
except (KeyboardInterrupt, SystemExit):
stop_event.set()
collection_thread.join()
logging_thread.join()
Yuck - Il n'y a pas besoin de sonder / dormir ici.
@TDelaney Vous avez probablement raison, et utilisez une valeur de délai d'attente sur obtenir code> pourrait être une meilleure façon de toute façon. Mais c'est comme ça que je l'ai jeté ensemble, il y a donc.
Je ne suis pas un expert en threading, mais dans votre Reportez-vous à la [Python Docs] pour modifier ceci en une file d'attente non bloquante Lire: Utilisez logData code> Fonction le premier d = INPUT_QUEUE.GET () code> bloque, c'est-à-dire si la file d'attente est vide. Il restera une attente pour toujours jusqu'à ce qu'un message de file d'attente soit reçu. C'est probablement pourquoi le fil code> logData code> ne se termine jamais, il est assis à attendre pour toujours pour un message de file d'attente. p>
.get (false) code> ou .get_nowait () code> - mais nécessite une manipulation d'exception pour des cas lorsque la file d'attente est vide. P>
Le problème est que votre enregistreur attend sur d = INPUT_QUEUE.GET () code> et ne vérifiera pas l'événement. Une solution consiste à ignorer complètement l'événement et à inventer un message unique qui indique à l'enregistreur de s'arrêter. Lorsque vous recevez un signal, envoyez ce message à la file d'attente. import threading
import Queue
import random
import time
def sim_collectData(input_queue, stop_event):
''' this provides some output simulating the serial
data from the data logging hardware.
'''
n = 0
while not stop_event.is_set():
input_queue.put("DATA: <here are some random data> " + str(n))
stop_event.wait(random.randint(0,5))
n += 1
print "Terminating data collection..."
input_queue.put(None)
return
def logData(input_queue):
n = 0
# we *don't* want to loop based on queue size because the queue could
# theoretically be empty while waiting on some data.
while True:
d = input_queue.get()
if d is None:
input_queue.task_done()
return
if d.startswith("DATA:"):
print d
input_queue.task_done()
n += 1
def main():
input_queue = Queue.Queue()
stop_event = threading.Event() # used to signal termination to the threads
print "Starting data collection thread...",
collection_thread = threading.Thread(target=sim_collectData, args=(input_queue, stop_event))
collection_thread.start()
print "Done."
print "Starting logging thread...",
logging_thread = threading.Thread(target=logData, args=(input_queue,))
logging_thread.start()
print "Done."
try:
while True:
time.sleep(10)
except (KeyboardInterrupt, SystemExit):
# stop data collection. Let the logging thread finish logging everything in the queue
stop_event.set()
main()
Notez que, à la fin, vous devez mettre autant de Aucun code> dans la file d'attente car il existe des threads bloqués.
@canaaerus - c'est un très bon point. Dans ce cas, il n'y a que 1 fil de travailleur, mais appeler le fait que N threads de travailleur a besoin de N messages de terminaison est un bel addition.
Basé sur la réponse de Tdelaney, j'ai créé une approche basée sur Itératrice. L'itérateur sort lorsque le message de terminaison est rencontré. J'ai également ajouté un compteur de combien de Il y a deux restrictions, que je n'avais pas besoin d'éliminer. Pour un Vous devez décider si vous voulez que vous voulez Donc, c'est le code: p> Oh, et j'ai écrit cela dans vous l'utiliseriez comme p> get code> -Calls sont en train de bloquer et un stop code> -method, qui envoie uniquement autant de messages de terminaison. Pour éviter une condition de race entre incrémentation et lecture du comptoir, je fixe un bit d'arrêt là-bas. En outre, je n'utilise pas Aucun code> comme message de terminaison, car il ne peut pas nécessairement être comparé à d'autres types de données lors de l'utilisation d'un PriorityQueue code>. Stop code> -method attend d'abord jusqu'à ce que la file d'attente soit vide avant de fermer les fils. La deuxième restriction est que je n'ai pas fait aucun code pour rendre la file d'attente réutilisable après stop code>. Ce dernier peut probablement être ajouté assez facilement, tandis que le précédent nécessite de faire attention à la concurrence et au contexte dans lequel le code est utilisé. P> arrêter code> à attendez également que tous les messages de terminaison soient consommés. J'ai choisi de mettre le nécessaire rejoindre code> là-bas, mais vous pouvez simplement le retirer. P> Python 3.2 Code>. Donc, après avoir réussi, p>
@Tdelaney a la meilleure solution. Toutes les réponses de vote / délai d'attente sont médiocres.
Vous pouvez bien sûr, vous pouvez toujours ajouter un délai d'attente à
INPUT_QUEUE.GET () code>