【问题标题】:Yielding in Boost.Asio Stackful CoroutineBoost.Asio Stackful Coroutine 中的收益
【发布时间】:2014-11-25 11:20:44
【问题描述】:

当使用 Boost.Asio stackful coroutines 时,我如何“手动”让另一个协程或异步操作有机会运行?例如,在发送对从 TCP 套接字接收的命令的响应之前,我需要执行长时间计算:

asio::spawn(strand_, [this, self](asio::yield_context yield)
{
    char data[256];
    while (socket_.is_open())
    {
        size_t n = socket_.async_read_some(boost::asio::buffer(data),
                                           yield);

        if (startsWith(data, "computePi"))
        {
            while (!computationFinished)
            {
                computeSomeMore();
                yield; // WHAT SHOULD THIS LINE BE?
            }

            storeResultIn(data);
            boost::asio::async_write(socket_, boost::asio::buffer(data, n),
                                     yield);
        }
    }
});

【问题讨论】:

    标签: c++ c++11 boost boost-asio coroutine


    【解决方案1】:

    比你想象的要简单:

    iosvc.post(yield);
    

    会成功的。

    iosvc借自@sehe的示例代码)

    【讨论】:

    • 这看起来确实更干净。
    【解决方案2】:

    你可以在 io_service 对象上调用poll_one()

    完整的工作示例:

    #include <boost/asio.hpp>
    #include <boost/asio/spawn.hpp>
    #include <boost/algorithm/string/predicate.hpp>
    #include <boost/thread.hpp>
    #include <iostream>
    
    namespace asio = boost::asio;
    using boost::asio::ip::tcp;
    using std::begin;
    using std::end;
    
    bool computationFinished = false;
    void computeSomeMore() {
        static int count = 0;
        if (count++>10)
        {
            computationFinished = true;
            std::cout << "Calculation finished\n";
        } else
        {
            std::cout << "Calculating...\n";
            boost::this_thread::sleep_for(boost::chrono::milliseconds(200));
        }
    }
    
    template <typename T> void storeResultIn(T& a) {
        std::fill(begin(a), end(a), '4');
    }
    
    int main()
    {
        asio::io_service iosvc;
        tcp::socket s(iosvc);
        tcp::resolver r(iosvc);
    
        tcp::acceptor a(iosvc, tcp::endpoint(tcp::v4(), 6767));
    
        a.accept(s);
        {
            asio::spawn(iosvc, [&iosvc,&s](asio::yield_context yield)
            {
                char data[256];
                while (s.is_open())
                {
                    size_t n = s.async_read_some(boost::asio::buffer(data), yield);
    
                    if (boost::algorithm::starts_with(data, "computePi"))
                    {
                        iosvc.post([]{std::cout << "I can still breath\n";}); // some demo work
                        iosvc.post([]{std::cout << "And be responsive\n";});
    
                        while (!computationFinished)
                        {
                            computeSomeMore();
                            iosvc.poll_one(); // this enables the demo work to be run
                        }
    
                        storeResultIn(data);
                        boost::asio::async_write(s, boost::asio::buffer(data, n), yield);
                    } else
                    {
                        std::cout << "Received unknown command '" << std::string(data, data+n) << "'\n";
                    }
                }
            });
        }
    
        iosvc.run();
        std::cout << "Bye bye\n";
    }
    

    当发送“computePi”时,服务器打印:

    Calculating...
    I can still breath
    Calculating...
    And be responsive
    Calculating...
    Calculating...
    Calculating...
    Calculating...
    Calculating...
    Calculating...
    Calculating...
    Calculating...
    Calculating...
    Calculation finished
    

    【讨论】:

    • 我喜欢你将我的 startsWithstoreResultIn 伪代码变成实际工作代码的方式!
    • 它是an indispensible skill。我要求自己尽可能测试我的答案。这是一项很棒的练习,而且非常有趣。
    • 在长时间的计算过程中,iosvc.poll() 而不是 iosvc.poll_one() 会让其余异步任务的响应速度更快吗?
    • 是的,当我获得声誉时,我也曾经写过工作示例。我从那个练习中学到了很多东西。
    • 我只是想强调一下,在轮询io_service 或将yield_context 发布到io_service 时都会导致协作单线程多任务,轮询io_service 避免了上下文切换开销,但来自处理程序的未处理异常将展开并破坏协程。
    猜你喜欢
    • 1970-01-01
    • 2013-07-03
    • 2019-09-19
    • 2012-08-15
    • 1970-01-01
    • 1970-01-01
    • 2016-08-07
    • 2011-01-22
    • 2015-03-29
    相关资源
    最近更新 更多