![[personal profile]](https://www.dreamwidth.org/img/silk/identity/user.png)
Судя по комментам к предыдущему посту, существует устойчивое подозрение, что сопрограммы имеют стек, и вообще кушают ресурсы. Хорошо, давайте померяем, это нетрудно. Создадим миллион сопрограмм и глянем расход памяти. Вот такой тестик.
Результат:co_void_t print(int n)
{
for (;;) {
std::cout << n << std::endl;
co_await co_await_t{};
}
}
int main(int argc, char **argv)
{
std::coroutine_handle<> continuation[1000000];
std::cout << "Using " << mallinfo().uordblks << " bytes after start.\n";
for (int i = 0; i < 1000000; i++)
continuation[i] = print(i);
std::cout << "Using " << mallinfo().uordblks << " bytes after coroutine allocation.\n";
for (int i = 0; i < 1000000; i++)
continuation[i].resume();
std::cout << "Using " << mallinfo().uordblks << " bytes after coroutine run.\n";
for (int i = 0; i < 1000000; i++)
continuation[i].destroy();
std::cout << "Using " << mallinfo().uordblks << " bytes after coroutine destroyed.\n";
return 0;
}
Делим разницу на количество сопрограмм: (48077488 - 77488) / 1000000 = 48 байтов на одну сопрограмму. Вполне недорогое удовольствие получается. Конечно, никакого собственного стека у сопрограмм не имеется, просто негде.Using 77488 bytes after start.
Using 48077488 bytes after coroutine allocation.
0
...
999999
Using 48077488 bytes after coroutine run.
Using 77824 bytes after coroutine destroyed.
no subject
Date: 2021-06-22 02:55 (UTC)В результате выгода в том, что пока сопрограмма активно не выполняется, ей не надо _пустое_место_ на стеке. И синхронные функции выполняются с той же эффективностью как обычно. А вот асинхронные функции (сопрограммы) имеют дополнительные накладные расходы по динамическому распределению памяти для стековых фреймов.
no subject
Date: 2021-06-22 03:08 (UTC)no subject
Date: 2021-06-22 03:50 (UTC)А как она реализована: сплошной массив у Threads, или список фреймов в Heap у coroutines - частности.
В любом случае где-то хранится цепь continuations вместо цепочки return addresses.
no subject
Date: 2021-06-22 03:57 (UTC)no subject
Date: 2021-06-22 05:13 (UTC)no subject
Date: 2021-06-22 06:18 (UTC)Всё равно нет никакой цепи continuations. Стандартная цепочка вложенных вызовов на обычном стеке.
no subject
Date: 2021-06-22 04:31 (UTC)no subject
Date: 2021-06-22 04:47 (UTC)no subject
Date: 2021-06-22 05:27 (UTC)Еще один вариант их представить - это несколько лямбд с общим контекстом. Запускается первая лямбда, она работает-работает пока не доходит до слова await. На этом месте она присоединяет к ожидаемому фьючеру лямбду-продолжение и возвращается. Когда фьючер будет готов, шедулер вызовет лямбду-продолжение и все продолжится. Когда же лямбда встречает слово return, она не просто так возвращается, а сначала сигналит в привязанный к контексту промиз/фьючер и освобождает контекст (выдывая деструкторы для всех объектов в нем).
Тут есть интересный момент: что если мы вызываем другую функцию, которая может внутри себя сделать await? Тогда та функция вернется в нашу, когда ее значение еще не готово. Ответ такой, что так делать не разрешается. Нельзя напрямую вызвать другую функцию, которая будет делать await, потому что та функция в таком разе обязана быть асинхронной. То есть, ее вызов транслируется в создание контекста и промиза/фьючера вызываемой асинхронной функции, привязывание к этому фьючеру своей лямбды-продолжения, шедуленье первой лямбды от новой функции, и возвращение из текущей лямбды.
no subject
Date: 2021-06-22 05:05 (UTC)no subject
Date: 2021-06-22 05:37 (UTC)no subject
Date: 2021-06-22 06:27 (UTC)Интересно, как же в ней работает alloca().
no subject
Date: 2021-06-22 07:06 (UTC)no subject
Date: 2021-06-22 07:17 (UTC)no subject
Date: 2021-06-22 07:31 (UTC)no subject
Date: 2021-06-22 08:06 (UTC)Локальным переменным соответствуют поля этого класса.
А каждому await - номер состояния.
no subject
Date: 2021-06-28 17:39 (UTC)Цель такова, что переменные живущие между приостановками будут в стеке, а те, которые переживают остановки - в activation frame вне стека
По ссылке есть картинки со стеком и регистрами
Там же есть ссылка на Proposed Draft Technical Specification, кому интересно. Мне, лично, не особо интересно, достаточно знать что работает. За прошедшие годы MSVC подшаманили так, что отладчик неплохо показывает на каком ты свете когда шагаешь по coroutine-enabled функции, но все же, я бы сказал, пока это не еще идеально. Хоть и пользоваться можно.
no subject
Date: 2021-06-28 18:45 (UTC)no subject
Date: 2021-06-22 09:30 (UTC)