2009-03-25 6 views
10

J'ai un programme python avec 2 threads (appelons-les 'source' et 'destination'). Le fil de départ envoie parfois un message au fil de destination avec quelques arguments. Le thread de destination sélectionne un message. doit appeler une fonction correspondante avec les ar- tives enregistrées dans le message.comment mettre une fonction et des arguments dans la file d'attente python?

Cette tâche peut être résolue de plusieurs façons. Le facile est de mettre un grand 'if ... if ... if' dans le cycle de sélection de message du thread de destination et d'appeler fonction en fonction du type de message reçu et des arguments sauvegardés. Mais cette se traduira par un énorme amounf de code (ou grande table de recherche) et l'ajout de nouveaux messages /fonction de gestionnaire évoluera étape supplémentaire pour écrire le code dans cycle de sélection de message.

Depuis python traite des fonctions comme des objets de première classe et ont tuples, je veux mettre une fonction et argumens dans un message, de sorte que les fils de destination prend un message, il suffit d'appeler un functon enregistré dans un message sans connaissance quelle est la fonction.

Je peux écrire un code pour une des fonctions avec le nombre spécifié d'arguments:

from Queue import * 
from thread import * 
from time import * 

q = Queue() 

def HandleMsg(arg1, arg2) : 
    print arg1, arg2 

def HandleAnotherMsg(arg1, arg2, arg3) : 
    print arg1, arg2, arg3 

def DestinationThread(a) : 
    while True : 
    (f, a, b) = q.get() 
    f(a, b) 

start_new_thread(DestinationThread, (0,)) 
print "start" 
sleep(1) 
q.put((HandleMsg, 1, 2)) 
sleep(1) 
print "stop" 

La question est: comment modifier un code afin que je puisse mettre() une fonction avec un nombre quelconque d'arguments dans la file d'attente ? par exemple HandleAnotherMsg()? En utilisant q.put ((HandleAnotherMsg, 1, 2, 3)) va augmenter une erreur de compilation :(

+0

Pouvez-vous poster l'erreur que vous obtenez? –

Répondre

24

donc simple:

def DestinationThread(a) : 
    while True : 
    items = q.get() 
    func = items[0] 
    args = items[1:] 
    func(*args) 
-2

Pourquoi


class MyQueue(Queue): 
    # by using *args, you can have a variable number of arguments 
    def put(self,*args): 
    for arg in args: 
     Queue.put(self,arg) 

ou pas sous-classe file d'attente? Pourquoi ne pas mettre une liste


list = [function_obj] 
for arg in function_args: 
    list.append(arg) 
queue.put(list) 
+0

Est-ce que quiconque--1'd cet esprit affiche pourquoi? –

+0

Il ne répond pas à la question. Chaque élément de la file d'attente doit encoder une fonction et un nombre inconnu d'arguments. Pousser chaque argument en tant que valeur distincte dans la file d'attente n'est pas utile. – cthulahoops

+0

En fait, le deuxième extrait de code est pertinent - ceux ci-dessus sont plus utiles cependant. – cthulahoops

8
from Queue import * 
from thread import * 
from time import * 

q = Queue() 

def HandleMsg(arg1, arg2) : 
    print arg1, arg2 

def HandleAnotherMsg(arg1, arg2, arg3) : 
    print arg1, arg2, arg3 

def DestinationThread() : 
    while True : 
    f, args = q.get() 
    f(*args) 

start_new_thread(DestinationThread, tuple()) 
print "start" 
sleep(1) 
q.put((HandleMsg, [1, 2])) 
sleep(1) 
q.put((HandleAnotherMsg, [1, 2, 3])) 
sleep(1) 
print "stop" 
0

On dirait que vous voulez utiliser la apply() intrinsèque ou son successeur:

def f(x. y): 
    print x+y 

args = (1, 2) 

apply(f, args) # old way 

f(*args)  # new way 
2

Je l'ai utilisé une construction similaire avant:

class Call: 
    def __init__(self, fn, *args, **kwargs): 
     self.fn = fn 
     self.args = args 
     self.kwargs = kwargs 

    def __call__(self): 
     return self.fn(*self.args, **self.kwargs) 


x = Call(zip, [0,1], [2,3], [4,5]) 

Vous devriez alors être en mesure de passer x à votre autre fil et appelez à partir de là:

x() # returns the same as zip([0,1], [2,3], [4,5]) 
0

Vous pouvez créer une classe de message abstraite avec une méthode d'exécution. Ensuite, pour chaque fonction qui doit être transmise via la file d'attente, sous-classe et implémente la fonction en tant que méthode d'exécution. L'unité d'exécution créatrice crée une instance de la sous-classe appropriée et la place dans la file d'attente. Le thread de réception obtiendra un objet de la file d'attente et exécutera aveuglément la méthode d'exécution.

Ceci est généralement appelé le modèle de commande (Gamma et al.)

Exemple:

class Message (object): 
    """abstract message class""" 
    def __init__(self, **kwargs): 
     self.kwargs = kwargs 

    def run(self): 
     pass 


class MessageOne (Message): 
    """one message class""" 
    def run(self): 
     # perform this emssage's action using the kwargs 

L'expéditeur instancier et envoyer un message:

queue.put(MessageOne(one='Eins', two='Deux')) 

Le récepteur reçoit simplement un objet de message et exécuter exécuter la méthode (sans avoir à it..else .. à travers les types de messages disponibles):

msg = queue.get() 
msg.run() 
11

Une autre option intéressante est simple y passer dans un lambda.

q.put(lambda: HandleMsg(1,2)) 
q.put(lambda: HandleAnother(8, "hello", extra="foo")) 

def DestinationThread() : 
    while True : 
     f = q.get() 
     f() 
Questions connexes