我有两个不同的函数f
和g
,它们使用不同的算法计算相同的结果。有时一个或另一个需要长时间,而另一个则快速终止。我想创建一个同时运行每个函数的新函数,然后从完成的第一个函数返回结果。
我想用更高阶函数创建该函数
h = firstresult(f, g)
在Python中实现这一目标的最佳方法是什么?
我怀疑解决方案涉及线程化。我想避免讨论GIL。
答案 0 :(得分:2)
我只想使用Queue。启动线程,第一个有结果的线程写入队列。
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
变量。由于我想保持这个例子简短,我只是假设那部分,并假设所有工人都有时间完成他们的工作,即使结果从未被读过。
根据提问者的要求,跳过关于Gil的讨论。 ; - )
答案 1 :(得分:1)
在新的工作线程中运行每个函数,2个工作线程将结果发送回1个项目队列中的主线程或类似的东西。当主线程收到胜利者的结果时,它会杀死(做python线程支持kill还是大声笑。)两个工作线程以避免浪费时间(一个函数可能需要几个小时,而另一个函数只需要一秒钟)。
如果需要,用过程替换单词thread。
答案 2 :(得分:1)
您需要在另一个进程(使用多处理)或另一个线程中运行每个函数。 如果两者都是CPU绑定的,多线程获得了很多帮助 - 完全由于GIL - 所以多处理就是这样。
如果返回值是一个pickleable(可序列化)对象,我创建的这个装饰器只是在后台运行该函数,在另一个过程中:
https://bitbucket.org/jsbueno/lelo/src
这不是你想要的 - 因为它们都是非阻塞的并且立即开始执行。这个装饰器的tirck就是当你试图使用返回值时阻塞(并等待函数完成)。
但另一方面 - 它只是一个完成所有工作的装饰师。
答案 3 :(得分: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)