Здравствуйте, vdimas, Вы писали:
V>Т.е. лямбда создаётся на стеке, но при сохранении её в std::function, происходит создание её копии в куче, потому что объект function устроен как-то так (схематично):
Естественно оно будет в общем случае в куче, так как происходит стирание типа, и соответственно размера.
EP>>И почему stackless корутина должна размещаться в каком-то другом месте?
V>Потому что, как и в случае std::string, для которого тоже есть некая оптимизация "маленьких" значений, реальный размер корутины заранее предугадать невозможно.
Это "потому что" никак не отвечает на поставленный вопрос. При стирании типа (как в std::function или .then), это справедливо и для передачи замыкания-лямбды, и для передачи корутины.
Как ответ на вопрос нужно показать чем объект-корутина отличается от лямбды в этом контексте, и почему её нужно размещать в другом месте. Ты же привёл общую для них характеристику, никак не обосновывающую необходимость отличий при размещении.
V>>>Я бы его разместил в объекте-наследнике того самого shared_state, который, в свою очередь, создаётся на куче.
EP>>А здесь можно вообще не менять ни сам future, ни лезть в его внутренности (типа наследования от shared_state). Потому что используем ли мы обычные продолжения, или объект-автомат (ручной или сгенерированный stackless coroutine) — это совершенно ортогонально тому где мы их размещаем.
V>Если используем future, то у нас в любом случае будет выделение памяти из кучи. Я лишь предлагаю свести кол-во выделений к минимуму, реализовав корутину как наследника future, либо как в случае с make_shared, просто расположив оба объекта в одном куске памяти (что фактически идентично с т.з. использования памяти). И я УВЕРЕН, что это именно так и будет. Даже могу поспорить на денюжку. )) Сорри, но это слишком очевидно, чтобы это "промухать". Не промухают, я уверен.
Подобная оптимизация возможна и для обычных замыканий, и для объектов-корутин которые я предлагаю — так как внутри .then мы знаем их размер, и можем аллоцировать их вместе с другими аллоцируемыми объектами за одну аллокацию (как в make_shared). Причём код оптимизации будет идентичным для обоих случаев, и авторам этой оптимизации вообще ничего не нужно знать о том что существуют ещё какие-то корутины.
В случае же proposal от microsoft, корутина аллоцируется своим отдельным аллокатором. И даже если оптимизация подобная make_shared и возможна — то автор future должен знать о том что у замыкания есть свой аллокатор, и писать отдельный код для этого случая.
Причём это относится не только к какой-то одной реализации future — а ко всем подобным. Специальный код должен быть в каждом случае.
EP>>Ты понимаешь что над корутинами из Boost.Asio можно сделать обёртку-итератор, в котором полностью будет хранится вся корутина? Или показать пример?
V>Не надо пример. Я, как раз, понимаю о чем речь, но ты не вникаешь в суть моих вопросов. Я всегда спрашиваю одно и то же — какой будет тип результирующего объекта?
Посмотри ещё раз
сюдаАвтор: Evgeny.Panasyuk
Дата: 12.06.15
— у корутины есть тип, имя этого типа задаётся объявлении корутины, то есть
struct coroutine, или с синтаксическим сахаром —
future<void> coroutine().
Это обычный тип, никакой магии.
V>Можно ли объявить переменную этого типа БЕЗ объявления корутины, а реальную корутину присвоить "потом" — как в твоём сценарии сериализации?
Конечно можно — это банальное type erasure, такое же как и в std::function.
V>>>Если твоя легковесная корутина будет содержать в себе другие корутины, то нужно эмулировать стек для их правильного обхода. И тут уже, извини, но без выделения памяти в куче — никак.
EP>>Зачем?
V>Для рекурсии. В т.ч. всевозможной неявной, через вызовы, скажем, захваченных в лямбду методов-переменных.
Только в случае корутинной рекурсии. То есть:
1) если в корутине вызывается обычная рекурсивная функция типа quicksort — то используется стандартный стэк.
2) если в корутине вызывается другая корутина, без рекурсии, то никакой динаимики — размер обеих известен во время компиляции.
3) если происходит простой рекурсивный вызов корутины, то получим ошибку incomplete type, который обходится динамикой, конкретнее — стэком корутин.
Не вижу в этом проблемы. В proposal от Microsoft динамика же будет во всех трёх случаях.
EP>>Вложенная корутина будет просто полем объекта внешней корутины
V>Ты забыл, что корутина у нас stack-less, поэтому стек ей придётся нарисовать ручками. И этот стек — штука динамическая, увы))
V>Поэтому — в куче.
Только в случае рекурсивных корутин
EP>>Вот пример, в нём нет никаких аллокаций в куче
V>(скипнул пример)
V>В этом примере нет, ес-но. Потому что нет недетерминированного стека вызовов.
А в proposal от Microsoft есть аллокации, хотя их вообще тут не должно быть.