asio 使用_future 而不是 yield[ec]
Posted
技术标签:
【中文标题】asio 使用_future 而不是 yield[ec]【英文标题】:asio use_future instead of yield[ec] 【发布时间】:2020-07-16 11:08:16 【问题描述】:我想制作期货容器,每个未来都是任务的无效结果,因此我可以在容器上使用wait_for_any,每个任务都是我目前使用yield_context实现的协程,并且在这个协程中启动返回ec的函数和我使用 ec 分析结果的结果。然后调用另一个协程传递相同的 yield_context 。 我想知道如何制作这个设计。 如果我将使用 use_future ,我如何将错误代码传递给 ec 而不是抛出它,除非除了抛出它之外别无他法,在这种情况下,我将尝试并捕获异步启动函数。 所有这些任务都将在 asio io_service 上发布、生成……。 这是我的主要代码部分: 这是任务的产物
boost::asio::spawn(GetServiceReference(), boost::bind(&HTTPRequest::Execute, boost::placeholders::_1, m_HttpClient_request_name, Get_mHTTPClient_Responses_Map()));
这是使用 yield_context 的协程
void HTTPRequest::Execute(boost::asio::yield_context yield_r, std::string request_name, std::map<std::string, boost::shared_ptr<HTTPResponse>>& mHTTPClient_Responses_Map)
resolver_iterator iterator_connect = boost::asio::async_connect(mSock, iterator_resolve, yield_r[ec]);
在Execute里面我们用ec来分析
if (ec == boost::system::errc::errc_t::success)
这里我们启动另一个协程传递相同的 yield_context
SendRequest(yield_r);
我想改变这一点,所以我有所有产生的 Execute 的期货容器,我不关心 Execute 的结果,因为我把它们放到成员类 Response 中。 但是我将来需要结果,以便我可以在容器上使用 wait_any 。
【问题讨论】:
【参考方案1】:如果您可以更改您的实现,请使用 async_result 模式。
这样您就可以将您的方法与任何方法(完成处理程序、yield 上下文或use_future
)一起使用。
我复制了here 中的独立示例以获得灵感:
综合演示
展示如何与 with 一起使用
coro 和产量[ec] coro 和产量 + 异常 std::future 完成处理程序Live On Coliru
#define BOOST_COROUTINES_NO_DEPRECATION_WARNING
#include <iostream>
#include <boost/asio.hpp>
#include <boost/asio/spawn.hpp>
#include <boost/asio/use_future.hpp>
using boost::system::error_code;
namespace asio = boost::asio;
template <typename Token>
auto async_meaning_of_life(bool success, Token&& token)
#if BOOST_VERSION >= 106600
using result_type = typename asio::async_result<std::decay_t<Token>, void(error_code, int)>;
typename result_type::completion_handler_type handler(std::forward<Token>(token));
result_type result(handler);
#else
typename asio::handler_type<Token, void(error_code, int)>::type
handler(std::forward<Token>(token));
asio::async_result<decltype (handler)> result (handler);
#endif
if (success)
handler(error_code, 42);
else
handler(asio::error::operation_aborted, 0);
return result.get ();
void using_yield_ec(asio::yield_context yield)
for (bool success : true, false )
boost::system::error_code ec;
auto answer = async_meaning_of_life(success, yield[ec]);
std::cout << __FUNCTION__ << ": Result: " << ec.message() << "\n";
std::cout << __FUNCTION__ << ": Answer: " << answer << "\n";
void using_yield_catch(asio::yield_context yield)
for (bool success : true, false )
try
auto answer = async_meaning_of_life(success, yield);
std::cout << __FUNCTION__ << ": Answer: " << answer << "\n";
catch(boost::system::system_error const& e)
std::cout << __FUNCTION__ << ": Caught: " << e.code().message() << "\n";
void using_future()
for (bool success : true, false )
try
auto answer = async_meaning_of_life(success, asio::use_future);
std::cout << __FUNCTION__ << ": Answer: " << answer.get() << "\n";
catch(boost::system::system_error const& e)
std::cout << __FUNCTION__ << ": Caught: " << e.code().message() << "\n";
void using_handler()
for (bool success : true, false )
async_meaning_of_life(success, [](error_code ec, int answer)
std::cout << "using_handler: Result: " << ec.message() << "\n";
std::cout << "using_handler: Answer: " << answer << "\n";
);
int main()
asio::io_service svc;
spawn(svc, using_yield_ec);
spawn(svc, using_yield_catch);
std::thread work([]
using_future();
using_handler();
);
svc.run();
work.join();
打印:
using_yield_ec: Result: Success
using_yield_ec: Answer: 42
using_yield_ec: Result: Operation canceled
using_yield_ec: Answer: 0
using_future: Answer: 42
using_yield_catch: Answer: 42
using_yield_catch: Caught: Operation canceled
using_future: Caught: Operation canceled
using_handler: Result: Success
using_handler: Answer: 42
using_handler: Result: Operation canceled
using_handler: Answer: 0
注意:为简单起见,我没有添加输出同步,因此输出可能会根据运行时执行顺序而混合
【讨论】:
我在搜索过程中研究了您的答案,并且它已经被加入书签,但我发现很难理解将完成令牌转换为处理程序时实际发生的情况。所有示例都谈到使用签名来形成处理程序类型。但形成的处理程序只是原型。处理程序没有主体。所以当异步操作完成时会调用什么????。关于我当前的问题,我仍然对操作的顺序感到困惑。例如:我将打包任务然后将它们添加到容器中。 ..但是我是从同一个线程还是不同线程启动 ios.run? 完成评论:我应该在哪里调用:wait_for_any???在我执行任务的同一个线程中或在 ios.run 之后“在相同或不同线程中”??? 现在我想我明白了处理程序的含义......它只是类型确定。并且有几种情况“我认为这些被称为类型特征”在编译时确定什么是类型处理程序传递,并据此他们将签名的参数传递给确定的类型“或部分参数,例如未来的情况”......所以如果它是函数对象,则将调用从用户传递的参数“lambda,bind, callback,function pointer" 或者在 use_future 的情况下它是未来的制造机制,或者它只是在有赌注协程的情况下切换上下文或者它是无赌注的 >>> 协程,以防 move(coro) 被传递。我是对的吗????现在我们如何使用这些不同的完成令牌与 spawn ,发布???我们可以避免构建 async_function 并使用 packaged_task将函数转换为返回未来的任务???生成的任务是否与 async_function 相同?我们将使用 async_function 和打包任务还是 using_future?? 你能发布一个新问题吗?一般来说,packaged_task 是不等价的,主要是因为它擦除了实际的处理程序类型。处理程序类型包括诸如何时使用链之类的信息。通过使用 packaged_task 擦除类型,ASIO 会丢失实际的处理程序类型并且无法维护语义。以上是关于asio 使用_future 而不是 yield[ec]的主要内容,如果未能解决你的问题,请参考以下文章
boost::asio 与 boost::unique_future
使用 use_future 提升 Asio async_send_to 多播不起作用
在 io_service.stop() 之后等待 boost asio 的未来将永远持续下去