Pergunta

Como faço para obter um tópico para retornar uma tupla ou qualquer valor da minha escolha de volta ao pai em Python?

Foi útil?

Solução

Eu sugiro que você instancie um Fila.queue Antes de iniciar o tópico, e passe como um dos args do fio: antes que o tópico termine, ele .puté o resultado na fila que recebeu como argumento. O pai pode .get ou .get_nowait à vontade.

As filas são geralmente a melhor maneira de organizar a sincronização e a comunicação do encadeamento em Python: são veículos intrinsecamente seguros para roscas e que passem de mensagens-a melhor maneira de organizar multitarefa em geral!-)

Outras dicas

Se você estava ligando para ingressar () para aguardar a conclusão do thread, você pode simplesmente anexar o resultado à própria instância do thread e recuperá -lo do thread principal após o retorno da junção ().

Por outro lado, você não nos diz como pretende descobrir que o thread está feito e que o resultado está disponível. Se você já tem uma maneira de fazer isso, provavelmente o apontará (e nós, se você nos contar) para a melhor maneira de divulgar os resultados.

Você deve passar em uma instância da fila como um parâmetro, então deve .put () seu objeto de retorno na fila. Você pode reunir o valor de retorno via fila.get () qualquer objeto que você coloque.

Amostra:

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)

Use para vários 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()

Eu uso essa implementação e funciona muito bem para mim. Eu gostaria que você faça isso.

Usar Lambda Para embrulhar sua função de thread de destino e passar o valor de retorno de volta ao fio pai usando um fila. (Sua função de destino original permanece inalterada sem o parâmetro extra da fila.)

Código de amostra:

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

Resultado:

4

Estou surpreso que ninguém tenha mencionado que você poderia simplesmente passar por isso:

>>> 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}

Talvez isso tenha grandes questões das quais não tenho conhecimento.

Outra abordagem é passar uma função de retorno de chamada para o thread. Isso fornece uma maneira simples, segura e flexível de retornar um valor ao pai, a qualquer momento do novo 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()

Você pode usar sincronizado fila módulo.
Considere que você precisa verificar um usuário Infos do banco de dados com um ID conhecido:

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

Agora você pode obter seus dados assim:

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

Bem, no módulo de rosqueamento do Python, existem objetos de condição associados a bloqueios. Um método acquire() retornará qualquer valor retornado do método subjacente. Para maiores informações: Objetos de condição de python

Baseado na sugestão do JCOMEAU_ICTX. O mais simples que encontrei. O requisito aqui era obter o status de saída STAUS de três processos diferentes em execução no servidor e acionar outro script se os três forem bem -sucedidos. Isso parece estar funcionando bem

  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

A função de wrapper a seguir envolverá uma função existente e retornará um objeto que aponta para o tópico (para que você possa ligar start(),join(), etc. nele), bem como acessar/visualizar seu eventual valor de retorno.

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

Parece bom, e o threading.Thread A classe parece ser facilmente estendida (*) com esse tipo de funcionalidade, por isso estou me perguntando por que já não está lá. Existe uma falha no método acima?

(*) Observe que a resposta de Husanu para esta pergunta faz exatamente isso, subclassificando threading.Thread resultando em uma versão onde join() fornece o valor de retorno.

Para programas fáceis, as respostas acima parecem um pouco como um exagero para mim. Eu envolveria a abordagem mutável:

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 em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top