Python concurrent.futures和ProcessPoolExecutor提供了一个简洁的界面来安排和监控任务。期货甚至provide a .cancel()方法:
取消():尝试取消通话。如果该呼叫当前正在执行且无法取消,则该方法将返回False,否则该呼叫将被取消,该方法将返回True。
不幸的是,在一个simmilar question(关于asyncio)中,回答声称运行任务是不可取消的,使用这个剪下来的文档,但文档不要说,只有当它们运行且不可执行时。
向进程提交multiprocessing.Events也是不可能的(通过参数执行此操作,如在multiprocess.Process中返回RuntimeError)
我想做什么?我想分区搜索空间并为每个分区运行任务。但它足以拥有一个解决方案,而且这个过程是CPU密集型的。那么,是否有一种实际可行的方法可以通过使用ProcessPool开始来抵消收益?
示例:
from concurrent.futures import ProcessPoolExecutor, FIRST_COMPLETED, wait
# function that profits from partitioned search space
def m_run(partition):
for elem in partition:
if elem == 135135515:
return elem
return False
futures = []
# used to create the partitions
steps = 100000000
with ProcessPoolExecutor(max_workers=4) as pool:
for i in range(4):
# run 4 tasks with a partition, but only *one* solution is needed
partition = range(i*steps,(i+1)*steps)
futures.append(pool.submit(m_run, partition))
done, not_done = wait(futures, return_when=FIRST_COMPLETED)
for d in done:
print(d.result())
print("---")
for d in not_done:
# will return false for Cancel and Result for all futures
print("Cancel: "+str(d.cancel()))
print("Result: "+str(d.result()))
答案 0 :(得分:4)
不幸的是,无法取消正在运行Futures
。我认为核心原因是在不同的实现上确保相同的API(它不可能中断正在运行的线程或协同程序)。
Pebble库旨在克服这个和其他限制。
from pebble import ProcessPool
def function(foo, bar=0):
return foo + bar
with ProcessPool() as pool:
future = pool.schedule(function, args=[1])
# if running, the container process will be terminated
# a new process will be started consuming the next task
future.cancel()
答案 1 :(得分:2)
我发现你的问题很有趣,所以这是我的发现。
我发现applet.icns
方法的行为与python文档中所述相同。至于你正在运行的并发功能,不幸的是,即使他们被告知这些功能也无法取消。如果我的发现是正确的,那么我认为Python确实需要更有效的.cancel()方法。
运行以下代码检查我的发现。
#{tag.date}
<强>更新强> 可以通过bash强制终止并发进程,但结果是主python程序也将终止。如果这不是您的问题,请尝试以下代码。
您必须在最后两个打印语句之间添加以下代码才能亲自查看。注意:只有在您没有运行任何其他python3程序时,此代码才有效。
.cancel()
答案 2 :(得分:2)
我不知道为什么concurrent.futures.Future
没有.kill()
方法,但您可以通过使用pool.shutdown(wait=False)
关闭进程池并杀死剩余的子进程来完成所需的操作手工流程。
创建一个杀死子进程的函数:
import signal, psutil
def kill_child_processes(parent_pid, sig=signal.SIGTERM):
try:
parent = psutil.Process(parent_pid)
except psutil.NoSuchProcess:
return
children = parent.children(recursive=True)
for process in children:
process.send_signal(sig)
运行代码,直到获得第一个结果,然后终止所有剩余的子进程:
from concurrent.futures import ProcessPoolExecutor, FIRST_COMPLETED, wait
# function that profits from partitioned search space
def m_run(partition):
for elem in partition:
if elem == 135135515:
return elem
return False
futures = []
# used to create the partitions
steps = 100000000
pool = ProcessPoolExecutor(max_workers=4)
for i in range(4):
# run 4 tasks with a partition, but only *one* solution is needed
partition = range(i*steps,(i+1)*steps)
futures.append(pool.submit(m_run, partition))
done, not_done = wait(futures, timeout=3600, return_when=FIRST_COMPLETED)
# Shut down pool
pool.shutdown(wait=False)
# Kill remaining child processes
kill_child_processes(os.getpid())