【问题标题】:asio use_future instead of yield[ec]asio 使用_future 而不是 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 。

【问题讨论】:

    标签: boost-asio future boost-thread


    【解决方案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 会丢失实际的处理程序类型并且无法维护语义。
    猜你喜欢
    • 2021-11-02
    • 2019-03-30
    • 1970-01-01
    • 2021-11-10
    • 1970-01-01
    • 2016-06-25
    • 2013-12-13
    • 2011-05-30
    • 1970-01-01
    相关资源
    最近更新 更多