web-dev-qa-db-ja.com

スレッドからの戻り値

Pythonでタプルまたは選択した値を親に返すスレッドを取得するにはどうすればよいですか?

55
Paul Joseph

スレッドを開始する前に Queue.Queue をインスタンス化し、スレッドの引数の1つとして渡すことをお勧めします。スレッドが終了する前に、.puts引数として受け取ったキューの結果。親は.getまたは.get_nowait思いのままに。

一般的に、キューはPythonでスレッドの同期と通信を調整するための最良の方法です。キューは本質的にスレッドセーフなメッセージ受け渡し手段です。一般的にマルチタスクを整理するための最良の方法です!-)

59
Alex Martelli

Join()を呼び出してスレッドの完了を待機している場合、結果をThreadインスタンス自体に添付し、join()が戻った後にメインスレッドから結果を取得できます。

一方、スレッドが完了し、結果が利用可能であることをどのように発見するつもりであるかについては教えません。既にそれを行う方法があれば、おそらくあなた(そしてあなたが私たちに教えてくれたのであれば私たち)に結果を出す最良の方法を示すでしょう。

12
Peter Hansen

Queueインスタンスをパラメーターとして渡す必要があります。その後、戻りオブジェクトをキューに.put()する必要があります。配置したオブジェクトに関係なく、queue.get()を介して戻り値を収集できます。

サンプル:

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)

複数のスレッドに使用:

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

私はこの実装を使用し、それは私にとって素晴らしい作品です。お願いします。

12
Fatih Karatana

lambdaを使用してターゲットスレッド関数をラップし、queueを使用してその戻り値を親スレッドに返します。 (元のターゲット関数は、追加のキューパラメーターなしで変更されません。)

サンプルコード:

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

出力:

4
7
Petr Vepřek

私はあなたがそれを変更可能にすることができると誰も言及していないことに驚いています:

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

おそらくこれには、私が気付いていない大きな問題があります。

7
jcomeau_ictx

別のアプローチは、スレッドにコールバック関数を渡すことです。これにより、新しいスレッドからいつでも親に値を返す簡単で安全かつ柔軟な方法が提供されます。

# 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()
5
Vijay Mathew

Synchronized queue モジュールを使用できます。
既知のIDを持つデータベースからユーザー情報を確認する必要があると考えてください。

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

これで、次のようなデータを取得できます。

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

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 __== '__main__':
    N = 100

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

    print "arr2: ", sortedArr
2
husanu

Jcomeau_ictxの提案に基づきます。私が出会った最も単純なもの。ここでの要件は、サーバーで実行されている3つの異なるプロセスから終了ステータスを取得し、3つすべてが成功した場合に別のスクリプトをトリガーすることでした。これはうまく機能しているようです

  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
1
f-z-N

さて、Pythonスレッドモジュールには、ロックに関連付けられた条件オブジェクトがあります。1つのメソッドacquire()は、基になるメソッドから返される値を返します。詳細については: Python条件オブジェクト

1
Ben Hayden

簡単なプログラムの場合、上記の答えは私にとってはやり過ぎのように見えます。私は変更可能なアプローチをennicenします:

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)
0
TheTrowser

次のラッパー関数は、既存の関数をラップし、スレッド(およびその上でstart()join()などを呼び出すことができるように)とアクセスの両方を指すオブジェクトを返します。 /最終的な戻り値を表示します。

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

見た目は良く、_threading.Thread_クラスはこの種の機能で簡単に拡張(*)されているようですので、なぜそこにないのか不思議に思っています。上記の方法に問題はありますか?

(*)この質問に対するhusanuの答えはまさにこれを行い、_threading.Thread_をサブクラス化すると、join()が戻り値を返すバージョンになります。

0
Andz