Pregunta

¿Cómo puedo obtener un hilo para devolver una tupla o cualquier valor de mi elección de nuevo a los padres en Python?

¿Fue útil?

Solución

Sugiero crear instancias de un Queue.Queue antes de iniciar el hilo, y pasarlo como una de args de la rosca: antes de que acabe el hilo, que .puts el resultado en la cola que recibió como un argumento. El padre puede .get o .get_nowait a voluntad.

Las colas son generalmente la mejor manera de organizar la sincronización de hilos y comunicación en Python: son intrínsecamente seguro para subprocesos, los vehículos de paso de mensajes - la mejor manera de organizar la multitarea en general -)

!

Otros consejos

Si estuviera llamando a unirse () para esperar a que el hilo para completar, simplemente podría adjuntar el resultado de la propia instancia de rosca y luego recuperarla desde el hilo principal después de la unión retornos ().

Por otro lado, no nos dicen cómo va a descubrir que el hilo está hecho y que el resultado está disponible. Si ya tiene una forma de hacer eso, es probable que apuntará (y nosotros, si usted fuera a decirnos) a la mejor manera de conseguir los resultados a cabo.

Debe pasar una instancia de cola como un parámetro, entonces debería .Put () el objeto de retorno en la cola. Usted puede reunir el valor de retorno a través de queue.get () cualquier objeto que se pone.

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)

El uso de 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 aplicación y funciona muy bien para mí. Me gustaría que lo haga.

Uso lambda para envolver su función de subproceso de destino y pasar su valor de retorno de nuevo a la rosca de los padres usando un cola . (La función de su objetivo original se mantiene sin cambios y sin parámetro de cola adicional.)

Código de ejemplo:

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 mencionó que sólo podía pasar una 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 importantes problemas de los que estoy al tanto.

Otro enfoque consiste en pasar una función de devolución de llamada a la rosca. Esto proporciona una manera simple, segura y flexible para devolver un valor a los padres, 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 sincronizada cola módulo.
Tenga en cuenta que usted necesita para comprobar unas informaciones de usuario de base de datos con un identificador conocido:

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

Ahora puede obtener los datos de la siguiente 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 threading Python, hay objetos de condición que se asocian a las cerraduras. Una acquire() método devolverá cualquier valor que se devuelve desde el método subyacente. Para más información: Condición Python Objetos

Sobre la base de la sugerencia de jcomeau_ictx. La más simple me encontré. Requisito aquí era conseguir staus estado de salida a partir de tres diferentes procesos que se ejecutan en el servidor y desencadenar una nueva secuencia de comandos si los tres son un éxito. 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 contenedor envolverá una función existente y devolver un objeto que apunta tanto a la rosca (por lo que se puede llamar start(), join(), etc. en ella), así como el acceso / ver su valor de retorno eventual.

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, por lo que me pregunto por qué no está ya allí. ¿Hay una falla con el método anterior?

(*) Nota de respuesta que Husanu para esta pregunta hace exactamente esto, threading.Thread de subclases que resulta en una versión en la join() da el valor de retorno.

Para los programas fáciles las answeres anteriores se ven un poco como una exageración para mí. Me 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)
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top