Re[7]: Вопрос по корутинам
От: landerhigh Пират  
Дата: 28.08.25 08:02
Оценка:
Здравствуйте, 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 в коде?

Мое, основанное на личном опыте, мнение — не стоит.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.