Python异步C++库

2024-03-28 12:43:49 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在努力做一些事情,希望这里有人能引导我度过难关

我有一个异步Python代码(AsiCIO),我在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_上下文,但我仍然需要一些无休止的过程,这样它就不会跳出范围,并且仍然会阻塞

m.def("start_client", &start_client, pybind11::call_guard<pybind11::gil_scoped_release>() );

谢谢你给我的建议


Tags: 代码ioclientasyncio客户端asyncdocdef
1条回答
网友
1楼 · 发布于 2024-03-28 12:43:49

要使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事件循环,这样就不需要线程,但这样做可能是一项重大任务

相关问题 更多 >