对象boost :: asio :: io_service的方法post()方法是否使用boost :: coroutines来执行处理程序中执行的短任务队列?这可以节省使用线程时花在同步上的资源,但却无法将任务移动到另一个线程。或者没有意义?
答案 0 :(得分:4)
尽我所知,Boost.Asio不使用协同程序。
从实现的角度来看,我认为使用协程(例如Boost.Coroutine提供的协程)会在调用发布的处理程序时引入开销。在事件循环知道可以调用处理程序的位置,它可以简单地调用处理程序而不必在trampoline函数中提升处理程序,以便可以在上下文中透明地调用它。一个协程。
Boost.Asio不知道处理程序的实际或预期运行时间,因此无论处理程序如何,它都必须执行相同的内部同步。当io_service
仅由单个线程处理时,可以通过在构造期间提供concurrency_hint来减轻同步开销。其他区域(如反应堆)可能仍需要执行同步。
最后,Boost.Asio不是强制执行上下文,而是提供强大的工具包,使用户能够为自己选择最佳选择。 Boost 1.54的当前Boost.Asio候选者通过其对以下方面的一流支持来增强这种体验:
Stackful Coroutines基于Boost.Coroutine。以下是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 example。
Stackless Coroutines已被提升为HTTP Server 4 example中记录的公共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
文档。
虽然我不知道使用协同程序构建异步调用链是否有性能优势,但我觉得它们的最大贡献是可维护性和可读性。我发现能够以同步方式读取和写入异步程序有助于减少反向控制流引入的复杂性,因为现在可以消除操作启动和完成之间的空间分离。