如何将 asyncio 与 boost.python 一起使用?

Posted

技术标签:

【中文标题】如何将 asyncio 与 boost.python 一起使用?【英文标题】:how to use asyncio with boost.python? 【发布时间】:2017-06-11 20:02:14 【问题描述】:

是否可以将 Python3 asyncio 包与 Boost.Python 库一起使用?

我有使用Boost.Python 构建的CPython C++ 扩展。用C++ 编写的函数可以工作很长时间。我想使用asyncio 调用这些函数,但是res = await cpp_function() 代码不起作用。

在协程内部调用cpp_function 会发生什么? 如何通过调用C++ 长时间工作的函数不被阻塞?

注意C++ 不做一些 I/O 操作,只是计算。

【问题讨论】:

【参考方案1】:

在协程内部调用 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)有哪些优点? @ІлляАнаніч 不客气! 1)如果您打算将此执行程序用于多个任务,您可以更改max_workers。 2) 我不知道cpp_function 到底在做什么,但如果它以某种方式处理字符串 - 它就是 CPU 操作。 I/O 操作通常与网络相关:例如从套接字读取。 3) 这就是为什么我认为你应该使用ProcessPoolExecutor。但是很容易检查我是否错了:尝试将ThreadPoolExecutor 用于cpp_function 并并行运行一些简单的任务(它可以每秒打印一些东西)。如果此任务在cpp_function 执行时被冻结,则线程不是一个选项。 嗯,我试过你的解决方案,但得到这个错误:TypeError: can't pickle Boost.Python.function objects @ІлляАнаніч,会发生什么:Python 在一个进程中从 Boost 函数获取一些数据并尝试将其传递给主进程。但并非每种数据都可以在进程之间传递。数据应该是可选的,请参阅link 了解更多信息。为了使事情正常运行,您不应该直接在执行程序中运行 Boost 函数,而是应该运行某种“代理”函数,将 boost 函数的结果转换为一些可挑选的对象并将该对象作为结果返回。不知道有没有其他方法可以在进程之间传递数据。

以上是关于如何将 asyncio 与 boost.python 一起使用?的主要内容,如果未能解决你的问题,请参考以下文章

如何将python asyncio与线程结合起来?

我如何将crossbar客户端(python3,asyncio)与tkinter集成

将 cProfile 与 asyncio 代码一起使用的正确方法是啥?

如何将 asyncio 与现有的阻塞库一起使用?

将 Qt Pyside2 与 asyncio await 语法一起使用?

如何将协程添加到正在运行的 asyncio 循环中?