Comments 9
очень крутая статья! узнал много нового!
Про Kotlin Coroutines добавить бы раздел, для полноты картины (они же в ветке Stackless тоже).
На каком еще стеке вызывающего - в 99% future будет обернут в таску токио и улетит в кучу, откуда waker её и будет шедулить. В целом сравнение Future раста и тех же Task в .net просто не корректно, потому что сами по future сами по себе не могу исполняться, это только часть async модели
Потому что в расте миллион объектов могут (в среднем будут) весить меньше чем сто тысяч в Питоне, не?
Просто напросто в расте в целом чуть оптимальнее используется память, т.к. меньше индерекций, плюс нет заголовков объектов*. Всё остальное не имеет особого значения.
Примечание*: про rc/arc немного другой разговор.
И Вы не совсем правы по поводу того, что все 4 упомянутых языка реализуют async fn как стейт-машину. Полностью как стейт-машину их реализует только раст и питон. C# и js используют гибридный подход: одну функцию они реализуют через стейт-машину, но вызов другой функции они обрабатывают через коллбэки.
А что в C++?
В .NET есть стандартный механизм AsyncMethodBuilder, который в том числе можно использовать и для пулинга стейтмашин - для ValueTask из коробки есть PoolingAsyncValueTaskMethodBuilder, для Task - можно заморочиться и написать свой пул+МетодБилдер.
Для ValueTask можно написать свой переиспользуемый IValueTaskSource на базе встроенного ManualResetValueTaskSourceCore.
С использованием всего этого можно очень, прямо вот ОЧЕНЬ серьёзно снизить количество и объём аллокаций.
Ну и NET 11 с Runtime Async не забываем.
Да как будто не удивительно, безотносительно того, что там под капотом. Вот если бы миллион корутин на раст занимали меньше, чем просто сто на пайтоне…
Почему миллион корутин на Rust весит меньше, чем сто тысяч на Python