【问题标题】:Async executor doesn't terminate process after run异步执行器在运行后不会终止进程
【发布时间】:2019-02-27 12:05:05
【问题描述】:

我希望在主要是异步 I/O 应用程序中拥有一个进程池,因为有时需要执行 CPU 密集型任务,而这些任务不应该让主应用程序停顿。此外,我想限制进程数。

根据文档,正确的方法是使用run_in_executor。下面的代码可以工作,但它不会在工作完成后终止进程。

import asyncio
from concurrent.futures.process import ProcessPoolExecutor

class App:
    def __init__(self):
        self.process_pool = ProcessPoolExecutor(4)
        self.loop = asyncio.get_event_loop()

    async def get_regular(self):
        return await regular()

    async def get_expensive(self):
        return await self.loop.run_in_executor(
            self.process_pool, expensive
        )

如何重用进程池中的进程或终止它们以遵守上限?

【问题讨论】:

  • 尝试过example 中的map() 方法吗?
  • 这不会在每次调用get_expensive 时创建一个新的进程池(有n 个进程)吗?此外,我只有单元素任务。
  • 进程 pool 的意义在于让进程为以后需要时做好准备。这个想法是您只需支付一次流程启动费用,然后从现有流程中获得即时响应。

标签: python concurrency python-asyncio


【解决方案1】:

如果你重用它,进程池会有奇怪的行为。所以我建议每次都创建一个新池并将其包装在with 结构中,如Example 所示。

如果您坚持重复使用池,管理其生命周期的责任就落在了您的肩上。使用后可以通过

杀死池中的所有子进程
self.process_pool.shutdown()

【讨论】:

  • 与只生成新进程的解决方案相比,这有多少开销?
  • 开销是启动子进程的时间,在我的机器上不到100毫秒。
  • 我所说的“奇怪”行为是关于将消息打印到标准输出。如果在expensive函数中不使用print,可以复用进程池。
  • 考虑到运行expensive 100ms 需要几秒钟的时间可以忽略不计。我现在每次都会生成一个新池。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-20
  • 2015-11-08
  • 2016-08-04
  • 1970-01-01
  • 1970-01-01
  • 2023-01-30
相关资源
最近更新 更多