如何使用asyncio与boost.python?

4

能否使用Python3的asyncio包与Boost.Python库一起使用?

我有一个使用Boost.Python构建的C++扩展。用C++编写的函数可能需要很长时间才能运行。我想使用asyncio调用这些函数,但是res = await cpp_function()代码无法工作。

  • cpp_function在协程内部调用时会发生什么?
  • 如何避免因调用长时间运行的C++函数而被阻塞?

注意C++没有进行某些I/O操作,只是计算。

1个回答

4
当在协程中调用cpp_function时会发生什么?
如果在任何一个协程中调用长时间运行的Python/C函数,它将冻结您的事件循环(在所有地方都会冻结所有协程)。
您应该避免这种情况。
如何通过调用长时间运行的C++函数而不被阻塞?
您应该使用run_in_executor在单独的线程或进程中运行函数。run_in_executor返回可等待的协程。
由于GIL的存在,您可能需要ProcessPoolExecutor(我不确定ThreadPoolExecutor是否适合您的情况,但建议您进行检查)。
以下是等待长时间运行代码的示例:
import asyncio
from concurrent.futures import ProcessPoolExecutor
import time


def blocking_function():
    # Function with long-running C/Python code.
    time.sleep(3)
    return True


async def main():        
    # Await of executing in other process,
    # it doesn't block your event loop:
    loop = asyncio.get_event_loop()
    res = await loop.run_in_executor(executor, blocking_function)


if __name__ == '__main__':
    executor = ProcessPoolExecutor(max_workers=1)  # Prepare your executor somewhere.

    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    try:
        loop.run_until_complete(main())
    finally:
        loop.run_until_complete(loop.shutdown_asyncgens())
        loop.close()

谢谢你的回答 :) 你能帮忙理解为什么将max_workers定义为1,并且为什么使用ProcessPoolThreads吗?因为Python文档中说线程用于I/O操作,而进程用于CPU工作。在我的案例中,协程调用了cpp_function只是从另一个字符串中获取一个字符串。这个cpp_function可能会占用所有的CPU资源,那么使用任何asyncio都没有意义。在我的情况下,asyncio(和Executors)有什么好处呢? - Illia Ananich
@ІлляАнаніч 不用谢!1)如果您计划将此执行器用于多个任务,则可以更改“max_workers”。2)我不知道“cpp_function”具体是做什么的,但如果它以某种方式处理字符串,则它是CPU操作。 I/O操作通常与网络相关:例如从套接字读取。 - Mikhail Gerasimov
1
这就是为什么我认为你应该使用ProcessPoolExecutor。但是验证我的想法很容易:尝试将ThreadPoolExecutor用于cpp_function并同时运行一些简单的任务(它可以每秒打印一些内容)。如果在执行cpp_function时这个任务被冻结了,那么线程就不是一个选项。 - Mikhail Gerasimov
嗯,我尝试了你的解决方案,但是出现了这个错误:TypeError: can't pickle Boost.Python.function objects - Illia Ananich
@ІлляАнаніч,发生了什么事:Python在一个进程中从Boost函数获取一些数据,并尝试将其传递到主进程。但并非所有类型的数据都可以从进程传递到进程。数据应该是可挑选的,请参见此链接以获取更多信息。为使事情正常工作,您不应直接在执行程序中运行Boost函数,而应该运行某种“代理”函数,该函数将Boost函数的结果转换为某个可挑选的对象,并将该对象作为结果返回。我不知道是否有其他方法可以在进程之间传递数据。 - Mikhail Gerasimov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接