Valor de retorno de hilo

¿Cómo obtengo un hilo para devolver una tupla o cualquier valor de mi elección al padre en Python?

Le sugiero que cree una instancia de Queue.Queue antes de iniciar el subproceso y que lo pase como uno de los argumentos del subproceso: antes de que el subproceso finalice, se .put el resultado de la cola que recibió como argumento. El padre puede .get o .get_nowait a voluntad.

En general, las colas son la mejor manera de organizar la sincronización y comunicación de subprocesos en Python: son vehículos de paso de mensajes intrínsecamente seguros, ¡la mejor manera de organizar la multitarea en general! -)

Si estaba llamando join () para esperar a que se completara el hilo, simplemente podría adjuntar el resultado a la instancia de Thread y luego recuperarlo del hilo principal después de que join () regrese.

Por otro lado, no nos dice cómo pretende descubrir que el hilo está terminado y que el resultado está disponible. Si ya tiene una forma de hacerlo, probablemente le indicará a usted (y a nosotros, si nos lo dijera) la mejor manera de obtener los resultados.

Debe pasar una instancia de la cola como un parámetro, luego debe .put () su objeto devuelto en la cola. Puede recostackr el valor de retorno a través de queue.get () cualquier objeto que ponga.

Muestra:

 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) 

Utilice para múltiples hilos:

 #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() 

Yo uso esta implementación y funciona muy bien para mí. Te deseo que lo hagas

Use lambda para envolver su función de hilo de destino y pasar su valor de retorno al hilo principal mediante una cola . (Su función de destino original permanece sin cambios sin un parámetro de cola adicional).

Código de muestra:

 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()) 

Salida:

 4 

Me sorprende que nadie mencione que solo se puede pasar 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} 

Tal vez esto tiene problemas importantes de los que no estoy enterado.

Otro enfoque es pasar una función de callback al hilo. Esto brinda una manera simple, segura y flexible de devolver un valor al padre, en cualquier momento desde el nuevo hilo.

 # 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() 

Puede utilizar el módulo de cola sincronizada.
Tenga en cuenta que necesita verificar las informaciones de un usuario de la base de datos con un ID conocido:

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

Ahora puedes obtener tus datos de esta manera:

 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 

Bueno, en el módulo de subprocesamiento de Python, hay objetos de condición que están asociados a lockings. Un método acquire() devolverá el valor devuelto por el método subyacente. Para más información: Python Condition Objects.

Basado en la sugerencia de jcomeau_ictx. La más sencilla que encontré. El requisito aquí era obtener el estado de estado de salida de tres procesos diferentes que se ejecutan en el servidor y activar otro script si los tres son exitosos. Esto parece estar funcionando 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 siguiente función de envoltura ajustará una función existente y devolverá un objeto que apunta tanto al subproceso (para que pueda llamar a start() , join() , etc.) así como a su acceso / vista de su valor de retorno final.

 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 

Se ve bien y la clase threading.Thread parece extenderse fácilmente (*) con este tipo de funcionalidad, así que me pregunto por qué no está ya allí. ¿Hay algún defecto con el método anterior?

(*) Tenga en cuenta que la respuesta de Husanu para esta pregunta hace exactamente esto, creando threading.Thread . threading.Thread resultan en una versión donde join() da el valor de retorno.

Para los progtwigs fáciles, las respuestas anteriores me parecen un poco excesivas. Me gustaría en-nicen el enfoque 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)