0

2 つの異なる関数fがあり、g異なるアルゴリズムで同じ結果を計算します。場合によっては、どちらか一方に長い時間がかかり、もう一方がすぐに終了することがあります。それぞれを同時に実行し、最初に終了した結果を返す新しい関数を作成したいと考えています。

その関数を高階関数で作りたい

h = firstresult(f, g)

Pythonでこれを達成する最良の方法は何ですか?

解決策にはスレッドが含まれていると思います。GIL についての議論は避けたいと思います。

4

4 に答える 4

2

これには単にキューを使用します。スレッドを開始し、結果がすぐにキューに書き込まれる最初のスレッドを開始します。

コード

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)

ライブデモ

http://ideone.com/jzzZX2

ノート

スレッドの停止はまったく別のトピックです。このためにstateは、定期的にチェックする必要のある変数をスレッドに追加する必要があります。この例を短くしたいので、私は単にその部分を想定し、結果が読み取られなくても、すべての作業者が作業を完了する時間を得ると想定しました。

質問者の要求に応じて、ギルに関する議論をスキップします。;-)

于 2013-02-08T01:14:08.143 に答える
1

新しいワーカースレッドで各関数を実行すると、2つのワーカースレッドが結果を1つのアイテムキューなどのメインスレッドに送り返します。メインスレッドが勝者から結果を受け取ると、時間の浪費を避けるために両方のワーカースレッドを強制終了します(Pythonスレッドはまだkillをサポートしていますか?笑)。

必要に応じて、スレッドという単語をプロセスに置き換えます。

于 2013-02-08T00:58:50.387 に答える
1

各関数は、別のプロセス(マルチプロセッシングを使用)または別のスレッドで実行する必要があります。両方がCPUにバインドされている場合、マルチスレッドは非常に役立ちます-まさにGILのために-したがって、マルチプロセッシングが方法です。

戻り値がピクルス可能な(シリアル化可能な)オブジェクトである場合、別のプロセスで関数をバックグラウンドで実行するだけのこのデコレータを作成しました。

https://bitbucket.org/jsbueno/lelo/src

どちらも非ブロッキングであり、すぐに実行を開始するため、これはまさにあなたが望むものではありません。このデコレータの欠点は、戻り値を使用しようとしたときと同じように、ブロックする(そして関数が完了するのを待つ)ことです。

しかし一方で、すべての作業を行うのは単なるデコレータです。

于 2013-02-08T01:00:09.677 に答える
1

今-他の答えに関する私の提案とは異なり、このコードはあなたが要求していることを正確に実行します:

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)
于 2013-02-08T04:36:48.203 に答える