我有两个不同的函数f
,g
用不同的算法计算相同的结果。有时一个或另一个需要很长时间,而另一个很快就会终止。我想创建一个同时运行每个函数的新函数,然后从第一个完成的函数返回结果。
我想用高阶函数创建那个函数
h = firstresult(f, g)
在 Python 中完成此任务的最佳方法是什么?
我怀疑解决方案涉及线程。我想避免讨论 GIL。
我有两个不同的函数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
需要定期检查的线程添加一些变量。由于我想保持这个例子简短,我只是假设这部分,并假设所有工人都有时间完成他们的工作,即使结果从未被读取。
按照提问者的要求跳过关于 Gil 的讨论。;-)
在一个新的工作线程中运行每个函数,两个工作线程将结果发送回一个 1 项队列或类似的东西中的主线程。当主线程从获胜者那里收到结果时,它会杀死(python 线程是否支持杀死?哈哈)两个工作线程以避免浪费时间(一个函数可能需要几个小时,而另一个只需要一秒钟)。
如果需要,将单词 thread 替换为 process。
您将需要在另一个进程(使用多处理)或不同的线程中运行每个函数。如果两者都受 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)