2009-12-01 2 views
0

J'ai des problèmes avec le lancement de threads à partir d'une liste de fonctions. Ils sont dans une liste car ce sont des fonctions spécifiques à la configuration. J'emballe les fonctions pour que je puisse stocker les résultats des fonctions dans 'self', mais quelque chose ne va pas de manière non-threadsafe que j'obtiens le bon nombre de threads démarrés, mais certaines instances ne sont pas correctes fonction. Voici l'exemple de code:Une fonction incorrecte est appelée sur plusieurs appels rapides au threading de Python. Thread()

import threading, time 

class runParallelTest(): 
    def __init__(self): 
     pass 

    def runList(self, functionList): 
     threadList = [] 
     for functionListIndex in range(0, len(functionList)): 
      newThread = threading.Thread(target=lambda:self._run_parallel_job(functionList[functionListIndex])) 
      newThread.start() 
      threadList.append(newThread) 
      # sleep delay that makes it all work fine. 
      #time.sleep(2) 

     # We wait for all the threads to complete and if any of them 
     # doesn't we report a failure. 
     for thread in threadList: 
      thread.join(3600*24) # 1 day better be enough 
      if thread.isAlive() == True: 
       raise Exception("thread.isAlive==True") 

    def _run_parallel_job(self, function): 
     results = function() 
     # store the results in a threadsafe way in self 
     # (I promise I'm using semaphores) 

def f(x): 
    print "f(%d) run" % x 
    return x 

if __name__ == '__main__': 
    rp = runParallelTest() 

    functionList = [ 
     lambda:f(0), 
     lambda:f(1), 
     lambda:f(2), 
     lambda:f(3), 
     lambda:f(4), 
     lambda:f(5), 
     lambda:f(6), 
     lambda:f(7), 
     ] 

    rp.runList(functionList) 

Quand je cours, je vois des choses comme ceci:

> python thread_problem.py 
f(0) run 
f(1) run 
f(2) run 
f(4) run 
f(5) run 
f(5) run 
f(6) run 
f(7) run 
> 

Alors que j'attends différents ordres dans les impressions, je pense que je devrais voir les numéros 0-7 sans répète, mais je ne le fais pas. Si j'ajoute time.sleep (2), le problème disparaît comme par magie, mais j'aimerais vraiment comprendre pourquoi cela ne fonctionne pas comme je le pense.

Merci beaucoup!

Répondre

1

Le problème est que functionList[functionListIndex] est évalué uniquement lorsque le lambda dans lequel il se trouve est exécuté (dans le thread). D'ici là, la valeur de functionListIndex peut changer.

Pour résoudre ce problème, vous pouvez passer un paramètre à la lambda qui sera évaluée au moment de la définition:

newThread = threading.Thread(target=lambda func=functionList[functionListIndex]: self._run_parallel_job(func)) 

Puisque les valeurs des paramètres par défaut des fonctions sont évaluées au moment de la définition, cela fonctionnera.

Une solution plus Pythonic est d'éviter le lambda et utiliser le paramètre args:

newThread = threading.Thread(target=self._run_parallel_job, args=(functionList[functionListIndex],)) 
+0

Ah! Maintenant, je comprends. Merci pour l'aide. –

Questions connexes