[英]How to properly use concurrent.futures with asyncio
我正在制作一个 FastAPI 应用程序原型,它的端点将使用 subprocess 模块启动长时间运行的进程。 显而易见的解决方案是使用 concurrent.futures 和 ProcessPoolExecutor,但是我无法获得我想要的行为。 代码示例:
import asyncio
from concurrent.futures import ProcessPoolExecutor
import subprocess as sb
import time
import random
pool = ProcessPoolExecutor(5)
def long_task(s):
print("started")
time.sleep(random.randrange(5, 15))
sb.check_output(["touch", str(s)])
print("done")
async def async_task():
loop = asyncio.get_event_loop()
print("started")
tasks = [loop.run_in_executor(pool, long_task, i) for i in range(10)]
while True:
print("in async task")
done, _ = await asyncio.wait(tasks, timeout=1)
for task in done:
await task
await asyncio.sleep(1)
def main():
loop = asyncio.get_event_loop()
loop.run_until_complete(async_task())
if __name__ == "__main__":
main()
从表面上看,这个示例工作正常,但生成的进程在执行完成后不会停止 - 我在ps aux | grep python
中看到所有 python 进程 ps aux | grep python
。 不应该等待完成的任务停止它吗? 最后,我不太关心执行的结果,它应该在后台发生并干净地退出 - 没有任何挂起的进程。
使用完 ProcessPool 后,必须通过显式调用它的shutdown()
方法或在 ContextManager 中使用它来关闭它。 我使用了 ContextManager 方法。
我不知道 subprocess.check_output 是做什么的,所以我把它注释掉了。
我还用对 asyncio.gather 的一次调用替换了你的无限循环,这将在 Executor 完成之前产生。
我在 Windows 上,所以为了观察进程的创建/删除,我查看了 Windows 任务管理器。 程序创建 5 个子进程,并在 ProcessPool 上下文管理器退出时再次关闭它们。
import asyncio
from concurrent.futures import ProcessPoolExecutor
# import subprocess as sb
import time
import random
def long_task(s):
print("started")
time.sleep(random.randrange(5, 15))
# sb.check_output(["touch", str(s)])
print("done", s)
async def async_task():
loop = asyncio.get_event_loop()
print("started")
with ProcessPoolExecutor(5) as pool:
tasks = [loop.run_in_executor(pool, long_task, i) for i in range(10)]
await asyncio.gather(*tasks)
print("Completely done")
def main():
asyncio.run(async_task())
if __name__ == "__main__":
main()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.