如何将 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 一起使用?的主要内容,如果未能解决你的问题,请参考以下文章
我如何将crossbar客户端(python3,asyncio)与tkinter集成
将 cProfile 与 asyncio 代码一起使用的正确方法是啥?