Здравствуйте, so5team, Вы писали:
L>>И во что он превращается и, главное, зачем с этим нужно разбираться при, гхм, "отладке"?
S>В обычную нечитаемую лапшу, надо полагать.
Настоящий самурай способен в нечитаемую лапшу вообще все превратить, только это не проблема корутин.
L>>Просто кое-кому просто захотелось поумничать
S>Кого-то просили привести пример преимущества короутин над КА, но кто-то что-то проигнорировал.
Так пример привели. И не один
S>>>но без оверхэда этих самых голых нитей.
L>>Оверхед на переключение контекста в случае стековых корутин примерно равен ему же для нитей (порядка 170 инструкций). Плюс память для стека. Удачи запустить 1000 корутин.
S>ЕМНИП, яндексовский userver с этой задачей спокойно справляется.
С чем именно? Двести инструкций на переключение никуда не денутся. Робкие попытки "растить" стек при необходимости, если не путаю, камрад Kowalke делал в ранних версиях boost::context, но имхо это такое себе.
С точки зрения обсуждаемой темы (запись асинхроного автомата в виде синхронного кода) единственное преимущество стековых корутин в том, что собственно код алгоритма будет написан вообще без co_yield, так yield будет вызываться внтури собственно кода который оборачивает I/O (где, собственно, асинхронность и возникает).
Рассмотрим пример из asio:
boost::asio::co_spawn(executor, echo(std::move(socket)), boost::asio::detached);
// ...
boost::asio::awaitable<void> echo(tcp::socket socket)
{
try
{
char data[1024];
for (;;)
{
std::size_t n = co_await socket.async_read_some(boost::asio::buffer(data), boost::asio::use_awaitable);
co_await async_write(socket, boost::asio::buffer(data, n), boost::asio::use_awaitable);
}
}
catch (std::exception& e)
{
std::printf("echo Exception: %s\n", e.what());
}
}
Предположим, что вместо корутин из стандарта у нас есть стековые корутины. Тогда вышеозначенный код "упрощается" до
void echo(tcp::socket socket)
{
try
{
char data[1024];
for (;;)
{
std::size_t n = socket.read_some(boost::asio::buffer(data));
write(socket, boost::asio::buffer(data, n));
}
}
catch (std::exception& e)
{
std::printf("echo Exception: %s\n", e.what());
}
}
здесь read_some и write переключают контекст на "родительскую" корутину, которая собственно, крутит select() в бесконечно цикле и переключет контекст обратно в обслуживающие корутины по доступности данных.
Стоит ли гнаться за отсутствим явных co_await/co_yield в коде?
Мое, основанное на личном опыте, мнение — не стоит.