我正在尝试实现一个以2个函数作为参数,同时运行两个函数,返回该函数的值的函数,该函数首先返回并杀死较慢的函数,然后再执行它。 我的问题是,当我尝试清空用于收集返回值的Queue对象时,我陷入了困境。 有没有更“正确”的方式来处理这种情况,甚至现有的模块?如果没有,谁能解释我在做什么错? 这是我的代码(上面函数的实现是'run_both()'):
import multiprocessing as mp
from time import sleep
Q = mp.Queue()
def dump_queue(queue):
result = []
for i in iter(queue.get, 'STOP'):
result.append(i)
return result
def rabbit(x):
sleep(10)
Q.put(x)
def turtle(x):
sleep(30)
Q.put(x)
def run_both(a,b):
a.start()
b.start()
while a.is_alive() and b.is_alive():
sleep(1)
if a.is_alive():
a.terminate()
else:
b.terminate()
a.join()
b.join()
return dump_queue(Q)
p1 = mp.Process(target=rabbit, args=(1,))
p1 = mp.Process(target=turtle, args=(2,))
run_both(p1, p2)
答案 0 :(得分:0)
下面是使用multiprocessing
调用2个或更多函数并返回最快结果的示例。但是,有几件事要注意。
multiprocessing
代码有时会引起问题。这个示例有效,但我确实遇到了尝试解决此问题的问题。if __name__ == '__main__'
子句内部开始,否则,如果主模块被另一个进程重新导入,它将再次运行。阅读多处理文档页面以获取更多信息。我还在此处添加了一些功能,以了解实际使用了哪个过程的结果。
import multiprocessing as mp
import time
import random
def task(value):
# our dummy task is to sleep for a random amount of time and
# return the given arg value
time.sleep(random.random())
return value
def process(q, idx, fn, args):
# simply call function fn with args, and push its result in the queue with its index
q.put([fn(*args), idx])
def fastest(calls):
queue = mp.Queue()
# we must pass the queue directly to each process that may use it
# or else on Windows, each process will have its own copy of the queue
# making it useless
procs = []
# create a 'mp.Process' that calls our 'process' for each call and start it
for idx, call in enumerate(calls):
fn = call[0]
args = call[1:]
p = mp.Process(target=process, args=(queue, idx, fn, args))
procs.append(p)
p.start()
# wait for the queue to have something
result, idx = queue.get()
for proc in procs: # kill all processes that may still be running
proc.terminate()
# proc may be using queue, so queue may be corrupted.
# https://docs.python.org/3.8/library/multiprocessing.html?highlight=queue#multiprocessing.Process.terminate
# we no longer need queue though so this is fine
return result, idx
if __name__ == '__main__':
from datetime import datetime
start = datetime.now()
print(start)
# to be compatible with 'fastest', each call is a list with the first
# element being callable, followed by args to be passed
calls = [
[task, 1],
[task, 'hello'],
[task, [1,2,3]]
]
val, idx = fastest(calls)
end = datetime.now()
print(end)
print('elapsed time:', end-start)
print('returned value:', val)
print('from call at index', idx)
示例输出:
2019-12-21 04:01:09.525575
2019-12-21 04:01:10.171891
elapsed time: 0:00:00.646316
returned value: hello
from call at index 1
答案 1 :(得分:0)
倒数第二行上的错字应显示为:
p2 = mp.Process(target=turtle, args=(2,)) # not p1
要使程序正常运行,最简单的更改就是添加:
Q.put('STOP')
到turtle()
和rabbit()
的末尾。
根据定义,如果您只是阅读消息队列并收到STOP
(其中之一已完成),那么您实际上也不需要一直循环监视进程是否处于活动状态,因此可以替换{{1 }}:
run_both()
您可能还需要考虑如果两个进程几乎同时将一些消息放入队列中会发生什么情况。他们可能会混在一起。也许考虑使用2个队列,或者将所有结果合并为一条消息,而不是将def run_both(a,b):
a.start()
b.start()
result = dump_queue(Q)
a.terminate()
b.terminate()
return result