2 つの異なる関数f
があり、g
異なるアルゴリズムで同じ結果を計算します。場合によっては、どちらか一方に長い時間がかかり、もう一方がすぐに終了することがあります。それぞれを同時に実行し、最初に終了した結果を返す新しい関数を作成したいと考えています。
その関数を高階関数で作りたい
h = firstresult(f, g)
Pythonでこれを達成する最良の方法は何ですか?
解決策にはスレッドが含まれていると思います。GIL についての議論は避けたいと思います。
2 つの異なる関数f
があり、g
異なるアルゴリズムで同じ結果を計算します。場合によっては、どちらか一方に長い時間がかかり、もう一方がすぐに終了することがあります。それぞれを同時に実行し、最初に終了した結果を返す新しい関数を作成したいと考えています。
その関数を高階関数で作りたい
h = firstresult(f, g)
Pythonでこれを達成する最良の方法は何ですか?
解決策にはスレッドが含まれていると思います。GIL についての議論は避けたいと思います。
これには単にキューを使用します。スレッドを開始し、結果がすぐにキューに書き込まれる最初のスレッドを開始します。
from threading import Thread
from time import sleep
from Queue import Queue
def firstresult(*functions):
queue = Queue()
threads = []
for f in functions:
def thread_main():
queue.put(f())
thread = Thread(target=thread_main)
threads.append(thread)
thread.start()
result = queue.get()
return result
def slow():
sleep(1)
return 42
def fast():
return 0
if __name__ == '__main__':
print firstresult(slow, fast)
スレッドの停止はまったく別のトピックです。このためにstate
は、定期的にチェックする必要のある変数をスレッドに追加する必要があります。この例を短くしたいので、私は単にその部分を想定し、結果が読み取られなくても、すべての作業者が作業を完了する時間を得ると想定しました。
質問者の要求に応じて、ギルに関する議論をスキップします。;-)
新しいワーカースレッドで各関数を実行すると、2つのワーカースレッドが結果を1つのアイテムキューなどのメインスレッドに送り返します。メインスレッドが勝者から結果を受け取ると、時間の浪費を避けるために両方のワーカースレッドを強制終了します(Pythonスレッドはまだkillをサポートしていますか?笑)。
必要に応じて、スレッドという単語をプロセスに置き換えます。
各関数は、別のプロセス(マルチプロセッシングを使用)または別のスレッドで実行する必要があります。両方がCPUにバインドされている場合、マルチスレッドは非常に役立ちます-まさにGILのために-したがって、マルチプロセッシングが方法です。
戻り値がピクルス可能な(シリアル化可能な)オブジェクトである場合、別のプロセスで関数をバックグラウンドで実行するだけのこのデコレータを作成しました。
https://bitbucket.org/jsbueno/lelo/src
どちらも非ブロッキングであり、すぐに実行を開始するため、これはまさにあなたが望むものではありません。このデコレータの欠点は、戻り値を使用しようとしたときと同じように、ブロックする(そして関数が完了するのを待つ)ことです。
しかし一方で、すべての作業を行うのは単なるデコレータです。
今-他の答えに関する私の提案とは異なり、このコードはあなたが要求していることを正確に実行します:
from multiprocessing import Process, Queue
import random
import time
def firstresult(func1, func2):
queue = Queue()
proc1 = Process(target=func1,args=(queue,))
proc2 = Process(target=func2, args=(queue,))
proc1.start();proc2.start()
result = queue.get()
proc1.terminate(); proc2.terminate()
return result
def algo1(queue):
time.sleep(random.uniform(0,1))
queue.put("algo 1")
def algo2(queue):
time.sleep(random.uniform(0,1))
queue.put("algo 2")
print firstresult(algo1, algo2)