如何使ProcessPoolExecutor中的任务像守护进程一样运行?

时间:2019-05-21 11:39:53

标签: python python-3.x python-multiprocessing python-asyncio

Python 3.6.6

这是代码:

import asyncio
import time
from concurrent.futures import ProcessPoolExecutor


executor_processes = ProcessPoolExecutor(2)


def calculate():
    while True:
        print("while")
        time.sleep(1)


async def async_method():
    loop_ = asyncio.get_event_loop()
    loop_.run_in_executor(executor_processes, calculate)
    await asyncio.sleep(1)
    print("finish sleep")

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.run_until_complete(async_method())
    print("main_thread is finished")

输出:

  

同时
  完成睡眠
  main_thread完成
  而
  而
  ...

我希望子进程将被终止,就像使用守护程序属性生成进程时一样:

import asyncio
import time
import multiprocessing


def calculate():
    while True:
        print("while")
        time.sleep(1)


async def async_method():
    proc = multiprocessing.Process(target=calculate)
    proc.daemon = True
    proc.start()
    await asyncio.sleep(1)
    print("finish sleep")

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.run_until_complete(async_method())
    print("main_thread is finished")

输出:

  

同时
  完成睡眠
  main_thread完成

问题:如何将loop_.run_in_executor(executor_processes, calculate)的行为更改为“类似守护程序”的行为?

1 个答案:

答案 0 :(得分:1)

您显示的代码显然只是一个小例子,以演示您希望实现的目标。我们不知道您的实际任务/问题。但老实说,我不相信您在这里的正确路径。

ProcessPoolExecutorconcurrent.futures标准库软件包的一部分。他们在调用submit()后将Future返回给呼叫者。 Future是尚未完成的计算结果的代理。这是一个承诺;尽管该术语在此情况下在技术上不太正确。有关区别,请参见Wiki page

这暗示着计算是 expected 在有限的时间内完成并产生结果。
这就是为什么Python中的ThreadPoolExecutorProcessPoolExecutor实现不允许您生成守护进程。要求承诺一个您实际上不希望实现的结果没有多大意义。

但是,可以直接回答问题的选项:

1-子类ProcessPoolExecutor
您可以拦截_adjust_process_count()p.daemon = True中新进程的创建和启动。但是,由于concurrent.futures在设计时并未考虑无限期运行的任务,因此不会有太大帮助。与multiprocessing不同,concurrent.futures.process定义了一个甚至不考虑守护进程的exit handler。它只是尝试join()进行所有操作,而无限循环可能会花费一些时间。

2-定义自己的退出处理程序:
您可以做multiprocessingconcurrent.futures.process都做的事情:定义退出处理程序,该处理程序在您的python进程即将关闭。 atexit可以帮助您:

import atexit

executor_processes = ProcessPoolExecutor(2)

def calculate():
    while True:
        print("while")
        time.sleep(1)

def end_processes():
    [proc.terminate() for proc in multiprocessing.active_children()]

async def async_method():
    [...]

if __name__ == '__main__':
    atexit.register(end_processes)
    loop = asyncio.get_event_loop()
    [...]

注意:这将终止所有活动的子进程,直到该进程结束为止。如果有子进程想要正常关闭,请保留一个句柄并在代码末尾执行该操作。
另外请注意,进程可以拒绝遵守terminate()kill()是您的最后度假胜地。