Question

Comment puis-je obtenir un fil pour retourner un tuple ou d'une valeur de mon choix au parent en Python?

Était-ce utile?

La solution

Je vous suggère de instancier un Queue.Queue avant de commencer le fil, et le transmettre en tant que l'un des arguments du fil: avant que le fil se termine, il .puts le résultat sur la file d'attente reçu comme argument. Le parent peut .get ou .get_nowait à volonté.

sont généralement Queues la meilleure façon d'organiser la synchronisation des threads et de la communication en Python: ils sont intrinsèquement thread-safe, les véhicules de passage de messages - la meilleure façon d'organiser multi-tâches en général -)

Autres conseils

Si vous appeliez joindre () pour attendre le fil pour terminer, vous pouvez simplement joindre le résultat à l'instance de fil lui-même, puis le récupérer à partir du thread principal après le retour join ().

Par contre, vous ne nous dites pas comment vous avez l'intention de découvrir que le fil est fait et que le résultat est disponible. Si vous avez déjà une façon de le faire, il pointera probablement vous (et nous, si vous deviez nous dire) à la meilleure façon de faire connaître les résultats.

Vous devez passer une instance de file d'attente comme paramètre alors vous devriez .put () votre objet de retour dans la file d'attente. Vous pouvez recueillir la valeur de retour via queue.get () quel que soit l'objet que vous mettez.

Exemple:

queue = Queue.Queue()
thread_ = threading.Thread(
                target=target_method,
                name="Thread1",
                args=[params, queue],
                )
thread_.start()
thread_.join()
queue.get()

def target_method(self, params, queue):
 """
 Some operations right here
 """
 your_return = "Whatever your object is"
 queue.put(your_return)

L'utilisation de plusieurs threads:

#Start all threads in thread pool
    for thread in pool:
        thread.start()
        response = queue.get()
        thread_results.append(response)

#Kill all threads
    for thread in pool:
        thread.join()

J'utilise cette mise en œuvre et il fonctionne très bien pour moi. Je vous souhaite le faire.

Utilisation lambda pour envelopper la fonction thread cible et passer sa valeur de retour vers le thread parent en utilisant une file d'attente . (Votre fonction cible originale reste inchangée sans paramètre de file d'attente supplémentaire.)

Exemple de code:

import threading
import queue
def dosomething(param):
    return param * 2
que = queue.Queue()
thr = threading.Thread(target = lambda q, arg : q.put(dosomething(arg)), args = (que, 2))
thr.start()
thr.join()
while not que.empty():
    print(que.get())

Sortie:

4

Je suis surpris que personne a mentionné que vous pouvez simplement passer un mutable:

>>> thread_return={'success': False}
>>> from threading import Thread
>>> def task(thread_return):
...  thread_return['success'] = True
... 
>>> Thread(target=task, args=(thread_return,)).start()
>>> thread_return
{'success': True}

peut-être cela a des problèmes majeurs dont je ne connais pas.

Une autre approche consiste à passer une fonction de rappel du fil. Cela donne un moyen simple, sûr et flexible pour retourner une valeur au parent, à tout moment du nouveau thread.

# A sample implementation

import threading
import time

class MyThread(threading.Thread):
    def __init__(self, cb):
        threading.Thread.__init__(self)
        self.callback = cb

    def run(self):
        for i in range(10):
            self.callback(i)
            time.sleep(1)


# test

import sys

def count(x):
    print x
    sys.stdout.flush()

t = MyThread(count)
t.start()

Vous pouvez utiliser Synchronized file d'attente le module .
Pensez vous devez vérifier un utilisateur infos de base de données avec un identifiant connu:

def check_infos(user_id, queue):
    result = send_data(user_id)
    queue.put(result)

Maintenant vous pouvez obtenir vos données comme ceci:

import queue, threading
queued_request = queue.Queue()
check_infos_thread = threading.Thread(target=check_infos, args=(user_id, queued_request))
check_infos_thread.start()
final_result = queued_request.get()

POC:

import random
import threading

class myThread( threading.Thread ):
    def __init__( self, arr ):
        threading.Thread.__init__( self )
        self.arr = arr
        self.ret = None

    def run( self ):
        self.myJob( self.arr )

    def join( self ):
        threading.Thread.join( self )
        return self.ret

    def myJob( self, arr ):
        self.ret = sorted( self.arr )
        return

#Call the main method if run from the command line.
if __name__ == '__main__':
    N = 100

    arr = [ random.randint( 0, 100 ) for x in range( N ) ]
    th = myThread( arr )
    th.start( )
    sortedArr = th.join( )

    print "arr2: ", sortedArr

Eh bien, dans le module Python filetage, il y a des objets de l'état qui sont associés aux serrures. Une méthode acquire() retourne la valeur retournée par la méthode sous-jacente. Pour plus d'informations: Condition Python objets

Basé sur la suggestion de jcomeau_ictx. Celui Je suis venu plus simple à travers. Exigence ici était d'obtenir le statut de sortie de trois processus Staus différents en cours d'exécution sur le serveur et déclencher un autre script si les trois réussissent. Cela semble fonctionner très bien

  class myThread(threading.Thread):
        def __init__(self,threadID,pipePath,resDict):
            threading.Thread.__init__(self)
            self.threadID=threadID
            self.pipePath=pipePath
            self.resDict=resDict

        def run(self):
            print "Starting thread %s " % (self.threadID)
            if not os.path.exists(self.pipePath):
            os.mkfifo(self.pipePath)
            pipe_fd = os.open(self.pipePath, os.O_RDWR | os.O_NONBLOCK )
           with os.fdopen(pipe_fd) as pipe:
                while True:
                  try:
                     message =  pipe.read()
                     if message:
                        print "Received: '%s'" % message
                        self.resDict['success']=message
                        break
                     except:
                        pass

    tResSer={'success':'0'}
    tResWeb={'success':'0'}
    tResUisvc={'success':'0'}


    threads = []

    pipePathSer='/tmp/path1'
    pipePathWeb='/tmp/path2'
    pipePathUisvc='/tmp/path3'

    th1=myThread(1,pipePathSer,tResSer)
    th2=myThread(2,pipePathWeb,tResWeb)
    th3=myThread(3,pipePathUisvc,tResUisvc)

    th1.start()
    th2.start()
    th3.start()

    threads.append(th1)
    threads.append(th2)
    threads.append(th3)

    for t in threads:
        print t.join()

    print "Res: tResSer %s tResWeb %s tResUisvc %s" % (tResSer,tResWeb,tResUisvc)
    # The above statement prints updated values which can then be further processed

La fonction d'emballage suivant enveloppera une fonction existante et retourner un objet qui pointe à la fois sur le fil (de sorte que vous pouvez appeler start(), join(), etc. sur elle), ainsi que l'accès / voir sa valeur de retour éventuel.

def threadwrap(func,args,kwargs):
   class res(object): result=None
   def inner(*args,**kwargs): 
     res.result=func(*args,**kwargs)
   import threading
   t = threading.Thread(target=inner,args=args,kwargs=kwargs)
   res.thread=t
   return res

def myFun(v,debug=False):
  import time
  if debug: print "Debug mode ON"
  time.sleep(5)
  return v*2

x=threadwrap(myFun,[11],{"debug":True})
x.thread.start()
x.thread.join()
print x.result

Il semble OK, et la classe threading.Thread semble être facilement étendu (*) avec ce type de fonctionnalité, alors je me demande pourquoi il n'y est pas déjà. Y at-il un défaut avec la méthode ci-dessus?

(*) Notez que la réponse à cette question Husanu exactement ce que fait, le sous-classement threading.Thread résultant dans une version où join() donne la valeur de retour.

Pour les programmes faciles les answeres ci-dessus ressemblent un peu exagéré pour moi. Je en-nicen l'approche mutable:

class RetVal:
 def __init__(self):
   self.result = None


def threadfunc(retVal):
  retVal.result = "your return value"

retVal = RetVal()
thread = Thread(target = threadfunc, args = (retVal))

thread.start()
thread.join()
print(retVal.result)
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top