简体   繁体   English

python的异步C++库

[英]Asynchronous C++ library for python

I'm struggling with something that hopefuly someone here will be able to guide me through please.我正在努力解决一些希望这里有人能够指导我完成的事情。

I have an asynchronous python code(asyncio), and I wrote simple asynchronous client in C++ that is very similiar to this one: https://www.boost.org/doc/libs/1_74_0/doc/html/boost_asio/example/cpp03/timeouts/async_tcp_client.cpp .我有一个异步 python 代码(asyncio),我用 C++ 编写了一个与这个非常相似的简单异步客户端: https : //www.boost.org/doc/libs/1_74_0/doc/html/boost_asio/example/ cpp03/timeouts/async_tcp_client.cpp For testing purposes I have server, which sends message every x seconds to client, when client connects.出于测试目的,我有服务器,当客户端连接时,它每 x 秒向客户端发送一次消息。 My plan is to be able to use this client from my python code but the problem is that currently it blocks my event loop and I don't really know what to do with it.我的计划是能够从我的 python 代码中使用这个客户端,但问题是目前它阻止了我的事件循环,我真的不知道如何处理它。 Is there a way to write library that would be awaitable from python code?有没有办法编写可以从 python 代码中等待的库?

Example C++ library:示例 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);
}

and also some minimal reproducible python code:还有一些最小的可重现的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())

I already tried releasing GIL and running io_context in a diffrent thread, but I still need some endless process so it won't jump out of scope and it still blocks.我已经尝试在不同的线程中释放 GIL 并运行 io_context,但我仍然需要一些无休止的过程,这样它就不会跳出范围并且仍然阻塞。

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

Any tips appreciated, thank you.任何提示表示赞赏,谢谢。

To make start_client not block the event loop, you need to release the GIL, and also hand it off to a thread pool (executor) managed by asyncio for that purpose:为了使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'
    )

Ideally one would connect asyncio and boost_asio event loops, so that threads are not needed, but doing so is likely to be a major undertaking.理想情况下,将连接 asyncio 和 boost_asio 事件循环,这样就不需要线程,但这样做可能是一项重大任务。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM