对象 boost::asio::io_service 的方法 post() 方法是否使用 boost::coroutines 来执行在处理程序中执行的短任务队列?这可以节省使用线程时用于同步的资源,但无法将任务移动到另一个线程。还是没有意义?
1 回答
据我所知,Boost.Asio 不使用协程。
从实现的角度来看,我想使用协程(例如Boost.Coroutine提供的协程)会在调用已发布的处理程序时引入开销。在事件循环知道可以调用哪些处理程序时,它可以简单地调用处理程序,而不必在蹦床函数中提升处理程序,以便可以在协程的上下文中透明地调用它。
Boost.Asio 不知道handlers的实际或预期的运行时间,因此它必须执行相同的内部同步而不管 handlers。当io_service
仅由单个线程处理时,可以通过在构造期间提供concurrency_hint来减轻同步开销。其他区域,例如反应堆,可能仍需要执行同步。
最后,Boost.Asio 并没有强加执行上下文,而是提供了一个强大的工具包,并授权用户为自己选择最佳选项。Boost 1.54 的当前 Boost.Asio 候选版本通过其一流的支持增强了这种体验:
基于 Boost.Coroutine 的Stackful Coroutines 。这是一个在协程
do_echo
上下文中执行的示例my_strand
。每个异步操作在启动异步操作后将控制权交还给调用线程,当调用完成处理程序时,控制权立即返回到上一个让步点之后。boost::asio::spawn(my_strand, do_echo); // ... void do_echo(boost::asio::yield_context yield) { try { char data[128]; for (;;) { std::size_t length = my_socket.async_read_some( boost::asio::buffer(data), yield); boost::asio::async_write(my_socket, boost::asio::buffer(data, length), yield); } } catch (std::exception& e) { // ... } }
Boost.Asio 提供了一个使用 Stackful Coroutines的完整echo_service 示例。
Stackless Coroutines已从HTTP Server 4 示例中提升为文档化的公共 API 。这些是作为 Duff 设备的变体实现的,但通过使用伪关键字
reenter
、yield
和,可以清楚地隐藏细节fork
。以下内容大致相当于上面的 Stackful Coroutine 示例:struct session : boost::asio::coroutine { tcp::socket my_socket_; char data_[128]; // ... void operator()(boost::system::error_code ec = boost::system::error_code(), std::size_t length = 0) { if (!ec) reenter (this) { for (;;) { yield my_socket_.async_read_some( boost::asio::buffer(data_), *this); yield boost::asio::async_write(my_socket_, boost::asio::buffer(data_, length), *this); } } } };
有关更多详细信息,请参阅
boost::asio::coroutine
文档。
虽然我不知道使用协程构建异步调用链是否有性能优势,但我觉得它们最大的贡献是可维护性和可读性。我发现能够以同步方式读写异步程序有助于降低反向控制流引入的复杂性,因为现在可以消除操作启动和完成之间的空间分离。