Re[26]: Mногопоточность: C++ vs Erlang vs другие
От: vdimas Россия  
Дата: 17.06.15 07:33
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

V>>Где ты предлагаешь разместить аналог своего asio::coroutine в future<>?


EP>Там же где и обычное обычное замыкание-продолжение.

EP>Абстрагируйся от asio::coroutine, представь простое замыкание-продолжение. Например у нас вместо:
EP>
EP>future<int> sum()
EP>{
EP>    int x = await foo();
EP>    int y = await bar();
EP>    return x + y;
EP>}
EP>
есть ручное нарезание на продолжения:

EP>
EP>future<int> sum()
EP>{
EP>    return foo().then([](int x)
EP>    {
EP>        return bar().then([=](int y)
EP>        {
EP>            return x + y;
EP>        });
EP>    });
EP>}
EP>
Где по-твоему здесь размещаются эти продолжения?


Оба раза в куче. ))
Т.е. лямбда создаётся на стеке, но при сохранении её в std::function, происходит создание её копии в куче, потому что объект function устроен как-то так (схематично):
template<>
class function<void()>
{
public:
  template<typename T>
  function(const T & closure)
    : closure_(makeClosure(closure))
  {}

  void operator()() {
    closure_->invoke();
  }

private:
  struct Closure {
    virtual void invoke() = 0;
  };

  template<typename T>
  static Closure * makeClosure(const T & closure) 
  {
    struct ClosureImpl {
      T closure_;
      virtual void invoke() { closure_(); }
    };
    
    return new ClosureImpl() {closure};
  };

  Closure * closure_;
};


Реальное исполнение отличается от приведенного попыткой оптимизации для маленьких замыканий, типа как для обычных адресов ф-ий, чтобы, если std::function создаётся от аргумента-простого адреса ф-ии, ничего в куче не создавать.


EP>И почему stackless корутина должна размещаться в каком-то другом месте?


Потому что, как и в случае std::string, для которого тоже есть некая оптимизация "маленьких" значений, реальный размер корутины заранее предугадать невозможно. Собсно, открой <functional> и посмотри на кол-во вызовов new.


V>>Я бы его разместил в объекте-наследнике того самого shared_state, который, в свою очередь, создаётся на куче.


EP>А здесь можно вообще не менять ни сам future, ни лезть в его внутренности (типа наследования от shared_state). Потому что используем ли мы обычные продолжения, или объект-автомат (ручной или сгенерированный stackless coroutine) — это совершенно ортогонально тому где мы их размещаем.


Если используем future, то у нас в любом случае будет выделение памяти из кучи. Я лишь предлагаю свести кол-во выделений к минимуму, реализовав корутину как наследника future, либо как в случае с make_shared, просто расположив оба объекта в одном куске памяти (что фактически идентично с т.з. использования памяти). И я УВЕРЕН, что это именно так и будет. Даже могу поспорить на денюжку. )) Сорри, но это слишком очевидно, чтобы это "промухать". Не промухают, я уверен.


V>>Другое дело:

V>>
V>>iterator<T> generate() resumable {
V>>  yield return 1;
V>>  yield return 2;
V>>};
V>>

V>>Т.к. тип iterator<> еще не специфирован, вполне возможно, что у него будет некое зарезервированное поле, в котором можно поместить целочисленную переменную — состояние автомата-корутины.

EP>Ты понимаешь что над корутинами из Boost.Asio можно сделать обёртку-итератор, в котором полностью будет хранится вся корутина? Или показать пример?


Не надо пример. Я, как раз, понимаю о чем речь, но ты не вникаешь в суть моих вопросов. Я всегда спрашиваю одно и то же — какой будет тип результирующего объекта? Можно ли объявить переменную этого типа БЕЗ объявления корутины, а реальную корутину присвоить "потом" — как в твоём сценарии сериализации?


V>>Если твоя легковесная корутина будет содержать в себе другие корутины, то нужно эмулировать стек для их правильного обхода. И тут уже, извини, но без выделения памяти в куче — никак.

EP>Зачем?

Для рекурсии. В т.ч. всевозможной неявной, через вызовы, скажем, захваченных в лямбду методов-переменных.


EP>Вложенная корутина будет просто полем объекта внешней корутины


Ты забыл, что корутина у нас stack-less, поэтому стек ей придётся нарисовать ручками. И этот стек — штука динамическая, увы))
Поэтому — в куче.


EP>Вот пример, в нём нет никаких аллокаций в куче

(скипнул пример)

В этом примере нет, ес-но. Потому что нет недетерминированного стека вызовов.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.