python 的异步 C++ 库
Asynchronous C++ library for python
我正在努力解决一些问题,希望这里有人能够指导我完成。
我有一个异步 python 代码 (asyncio),我用 C++ 编写了一个简单的异步客户端,它与这个非常相似:https://www.boost.org/doc/libs/1_74_0/doc/html/boost_asio/example/cpp03/timeouts/async_tcp_client.cpp。出于测试目的,我有服务器,当客户端连接时,它每 x 秒向客户端发送一次消息。我的计划是能够从我的 python 代码中使用这个客户端,但问题是目前它阻止了我的事件循环,我真的不知道如何处理它。有没有一种方法可以编写可从 python 代码等待的库?
示例 C++ 库:
void start_client(std::string ip, std::string port)
{
try
{
boost::asio::io_context io_context;
tcp::resolver r(io_context);
// https://www.boost.org/doc/libs/1_74_0/doc/html/boost_asio/example/cpp03/timeouts/async_tcp_client.cpp
client c(io_context);
c.start(r.resolve(ip, port));
io_context.run(); // this will block :(
}
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << "\n";
}
}
#include <pybind11/pybind11.h>
PYBIND11_MODULE(async_client, m) {
m.def("start_client", &start_client);
}
以及一些最小的可重现 python 代码:
import asyncio
import async_client
async def client():
async_client.start_client('0.0.0.0', '3000') # this will block :(
async def test():
while True:
print('This will not get displayed!')
await asyncio.sleep(3)
async def main():
await asyncio.gather(client(), test())
if __name__ == '__main__':
asyncio.run(main())
我已经尝试在不同的线程中释放 GIL 和 运行 io_context,但我仍然需要一些无休止的过程,这样它就不会跳出范围,它仍然会阻塞。
m.def("start_client", &start_client, pybind11::call_guard<pybind11::gil_scoped_release>() );
感谢任何提示,谢谢。
为了start_client
不阻塞事件循环,您需要释放 GIL,并将其移交给由 asyncio 管理的线程池(执行程序):
async def client():
loop = asyncio.get_event_loop()
await loop.run_in_executor(
None, async_client.start_client, '0.0.0.0', '3000'
)
理想情况下,可以连接 asyncio 和 boost_asio 事件循环,这样就不需要线程了,但这样做可能是一项艰巨的任务。
我正在努力解决一些问题,希望这里有人能够指导我完成。
我有一个异步 python 代码 (asyncio),我用 C++ 编写了一个简单的异步客户端,它与这个非常相似:https://www.boost.org/doc/libs/1_74_0/doc/html/boost_asio/example/cpp03/timeouts/async_tcp_client.cpp。出于测试目的,我有服务器,当客户端连接时,它每 x 秒向客户端发送一次消息。我的计划是能够从我的 python 代码中使用这个客户端,但问题是目前它阻止了我的事件循环,我真的不知道如何处理它。有没有一种方法可以编写可从 python 代码等待的库?
示例 C++ 库:
void start_client(std::string ip, std::string port)
{
try
{
boost::asio::io_context io_context;
tcp::resolver r(io_context);
// https://www.boost.org/doc/libs/1_74_0/doc/html/boost_asio/example/cpp03/timeouts/async_tcp_client.cpp
client c(io_context);
c.start(r.resolve(ip, port));
io_context.run(); // this will block :(
}
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << "\n";
}
}
#include <pybind11/pybind11.h>
PYBIND11_MODULE(async_client, m) {
m.def("start_client", &start_client);
}
以及一些最小的可重现 python 代码:
import asyncio
import async_client
async def client():
async_client.start_client('0.0.0.0', '3000') # this will block :(
async def test():
while True:
print('This will not get displayed!')
await asyncio.sleep(3)
async def main():
await asyncio.gather(client(), test())
if __name__ == '__main__':
asyncio.run(main())
我已经尝试在不同的线程中释放 GIL 和 运行 io_context,但我仍然需要一些无休止的过程,这样它就不会跳出范围,它仍然会阻塞。
m.def("start_client", &start_client, pybind11::call_guard<pybind11::gil_scoped_release>() );
感谢任何提示,谢谢。
为了start_client
不阻塞事件循环,您需要释放 GIL,并将其移交给由 asyncio 管理的线程池(执行程序):
async def client():
loop = asyncio.get_event_loop()
await loop.run_in_executor(
None, async_client.start_client, '0.0.0.0', '3000'
)
理想情况下,可以连接 asyncio 和 boost_asio 事件循环,这样就不需要线程了,但这样做可能是一项艰巨的任务。