首页 > 解决方案 > 如何使用(非增强)Asio 编写自己的异步操作?

问题描述

我想基于Asio 1.19.2编写自己的异步函数(不带 boost)。

其动机是创建一个使用类似JSON-RPC的协议(不完全是 JSON-RPC)的接口。

在套接字上它看起来像

--> { "method": "subtract", "params": [42, 23], "id": 1 }
<-- ... some irrelevant notifications, etc.
<-- { "result": 19, "id": 1 } <-- ID matches initial call

我已经用std::futures (没有 Asio)解决了这个问题。该方法签名类似于:

// near useless, because futures don't allow for continuation
std::future<std::string> json_rpc(std::string method, json::array args);

为了实现这一点,我只需要:

我如何将这种基于未来的方法转换为基于 asio 的方法,它具有与 eg 类似的界面async_read_until?换句话说,我想实现类似的东西:

template <typename CompletionToken>
void async_json_rpc(std::string method, json::array args, CompletionToken&& completion_token);

从 beast 中找到了本教程,但它使用 Boost.Beast,似乎已经过时,并且它唯一的异步部分是它调用的地方async_read_some。我的代码并不能真正利用这些 asio async_“原语”,因为我的完成处理程序需要在操作系统控制之外的某个时间被调用。

我还从 asio docs 中找到了这些示例,但它们具有仅包装其他async_调用的相同限制。对于应用程序代码,它们也变得越来越复杂。

我想,我的问题的核心是:我有一个异步函数,它基本上就像它asio::use_future用作它的CompletionToken. 我如何让它使用任何一种CompletionTokenpromise.set_value()asio 完成处理程序的等价物是什么?

我对简单易懂的解决方案非常感兴趣,因此我不是团队中唯一能够维护这些功能的人。

为了进一步澄清(根据我的评论):

我已经实现了“服务线程的服务完成”,但我只支持期货(如果我正在编写一个 asio 异步方法,就好像我只做了 asio::use_future 重载)。我在问如何支持 CompletionHandlers,即如何编写其他可以采用 lambdas 或 yield_contexts 的 async_* 重载。

标签: c++asynchronousc++17boost-asio

解决方案


我想您是在问如何实施“链”?我做过类似的事情。

通常,您需要一个为队列提供服务的工作线程。它将循环并执行队列中的每个项目,但当它为空时会休眠。如有必要,将某些内容添加到队列中会通知线程唤醒。

一个更好的变体是使用线程池和公共队列,如果有太多线程,则修剪多余的线程,如果现有线程的工作过多,则创建更多线程。理想情况下,这需要操作系统支持(我已经为 Windows 完成端口实现了这个)。

当你想做一些异步的事情时,你把承诺放在队列上,而不是为此启动一个专用线程。

或者......你在看协程,co_await在 C++ 中进行调用吗?


推荐阅读