Войти
ФлеймФорумПроЭкты

Ü (Programmiersprache) (77 стр)

Страницы: 176 77 78 7999 Следующая »
#1140
20:00, 10 дек 2022

Dmitry_Milk
> А действительно ли нужно несколько стеков? Ведь если внутри async-функции
> вызывается обычная функция - она обязана завершиться сразу же, нигде в этой
> иерархии вызовов уже не может возникнуть await
Зависит от языка, в некоторых async-функции ничем от обычных не отличаются.

#1141
22:20, 10 дек 2022

Dmitry_Milk
> То есть, вроде бы достаточно присобаченнго к фьючеру состояния фрейма самой асинк-функции (и этот фрейм конечной величины, даже если включает в себя переменные всех областей видимости).
Точнее, идентификатор текущей точки ожидания + все видимые переменные. В случае рекурсивного вызова может быть неограниченного размера. Без рекурсии это конечный variant<Frame1, Frame2, ...> и если в языке есть продвинутое метапрограммирование, то можно автоматом сгенерировать функцию сериализации, пройдясь по всем членам.

#1142
22:37, 10 дек 2022

}:+()___ [Smile]
> В случае рекурсивного вызова может быть неограниченного размера.

Если его сделать как Box<variant<...>>, то вроде все упрощается. Насчет эффективности - еще надо посмотреть на то, как часто надо мувить фьючер (и надо ли вообще). Бокс мувится элементарно, а с обычным значением - там еще и палки в колеса с невозможностью перемещения при наличии во фрейме ссылок на значения в том же фрейме (из-за чего, например, в том же расте пляски с Pin/Unpin).

#1143
(Правка: 23:05) 23:03, 10 дек 2022

Погуглил. Вроде в Rust и в Крестах используются беcстековые корутины. Думаю, в этом есть некий смысл, а значит, мне тоже имеет смысл делать их именно таковыми.

Нарыл в документации (нормальной, не для нубов) кое-что:
https://doc.rust-lang.org/reference/expressions/await-expr.html

Пока у меня есть следующее понимание: корутины, это на самом деле некие машины состояний, порождённые из линейной записи программы. Объект, порождённый "вызовом" async есть такая машина состояний, которая хранит в себе аргументы и локальные переменные а также текущую точку входа. Потом эту машину состояний (как некий функциональный объект) можно вызывать, при этом каждый вызов как-то изменяет её состояние. Вызывать её можно до тех пор, пока не будет достигнуто окончательное состояние, и при этом (тут я не до конца уверен) может получиться результат выполнения корутины.

Глядя на llvm-код примеров корутин из крестов я обнаружил следующее: там состояние корутины сохраняется в неком поле, при вызове корутины происходит переход к нужному месту в коде на основе значения состояния.

#1144
23:07, 10 дек 2022

Генераторы работают вроде схожим  образом. Там просто на каждом вызове возвращается некое значение.

#1145
23:55, 10 дек 2022

Panzerschrek[CN]
> Генераторы работают вроде схожим  образом

В питоне асинки эволюционировали из генераторов. Там до сих пор таском для асинк-бакэнда может быть как async-функция, так и генератор.

Panzerschrek[CN]
> Нарыл в документации (нормальной, не для нубов) кое-что

await в расте работает не с корутиной, а с более абстракной штукой - фьючером Future<T>, который и есть тот самый "Объект, порождённый "вызовом" async". То есть, корутину можно вызывать и без await (что можно сделать и из обычной функции), просто сразу же получив Future<T> вместо T. Правда потом с этим фьючером придется разбираться вручную (либо передать его выше)

А await просто сахар для  "раздевания" Future<T> по его готовности.

#1146
9:30, 11 дек 2022

Обнаружил такую не очень приятную вещь:

Все аргументы и локальные переменные корутины надо складывать в какую-то структуру, дабы они после вызова сохранялись. И если так прямо и делать, то всё будет даже нормально работать. Но есть один нюанс: будет некоторая переголова по размеру структуры. Ведь есть переменные с непересекающимся временем жизни, а ещё есть переменные, которые живут только от await до await и сохранять их вообще не надо.
В результате размер этой структуры может быть сильно больше размера стека фрейма для аналогичной простой функции. А ещё надо учесть, что при вызове корутины из корутины и все переменные последней тоже надо сохранять.

#1147
21:02, 11 дек 2022

Panzerschrek[CN]
> Но есть один нюанс: будет некоторая переголова по размеру структуры. Ведь есть
> переменные с непересекающимся временем жизни

variant (а точнее аналог растовского enum), разбивая как по началам/концам областей видимости, так и по await-ам (когда разные варианты будут иметь одинаковую структуру). Тогда не придется отдельно диспетчить await-ы - нужный участок корутины автоматом будет диспетчиться при паттерн-матчинге этого варианта, а заодно - не придется думать о деструкторах.

Но вообще кажется, что лучше не идти по пути Раста и не реализовывать эту структуру как обычную strucr/enum языка, а считать ее специальной языковой конструкцией с особенными свойствами (скажем, ее нельзя мувить, если в корутине есть ссылки на переменные этой же корутины). Иначе как в Расте получится невозможным реализовывать async-бакэнды без unsafe (потому что ссылки в этой структуре приходится заменять указателями, которые потом надо разадресовывать).

#1148
9:41, 12 дек 2022

Dmitry_Milk
> variant
Не подходит, ибо в различных состояний  по крайней мере некоторые переменные будут присутствовать.

> не придется думать о деструкторах
Что значит не придётся? Очень даже придётся.

> не реализовывать эту структуру как обычную strucr/enum языка
Ну это чисто технический момент, как это по факту называть.

> скажем, ее нельзя мувить
Совсем забыл про это. Теперь понятно, зачем нужен Pin для вызова poll в Rust-овский корутинах.
И да, я язык с самого начала проектировал так, чтобы в нём неперемещаемых объектов не было, ибо неперемещаемость добавляет сложностей в дизайне языка. С корутинами придётся или таки вводить неперемещаемость, или делать вызов корутины unsafe, чтобы обязать программиста гарантировать отсутствие перемещения.

#1149
9:52, 12 дек 2022

Panzerschrek[CN]
> чтобы в нём неперемещаемых объектов не было
А как же мютексы и атомики?
Их перемещение выглядит неправильно.

#1150
(Правка: 10:05) 10:02, 12 дек 2022

/A\
> А как же мютексы и атомики?
> Их перемещение выглядит неправильно.
А в чём их проблема? Что будет, если их переместить?

Справедливости ради, стоит заметить, что ни того ни другого (в привычном понимании) в Ü нету. Вместо atomic типов есть только atomic операции (чтение, модификация). Сместь мьютексов есть нечто вроде shared_ptr с rwlock внутри.

#1151
10:44, 12 дек 2022

Panzerschrek[CN]
> С корутинами придётся или таки вводить неперемещаемость, или делать вызов корутины unsafe, чтобы обязать программиста гарантировать отсутствие перемещения.
Перемещаемость во многом эквивалентна сериализуемости, поэтому если осилишь сериализацию корутин, то автоматом получишь перемещаемость.

#1152
10:49, 12 дек 2022

}:+()___ [Smile]
> то автоматом получишь перемещаемость
Суть перемещаемости - возможность тупо позвать memcpy. Свистопляски с исправлением ссылок после перемещения и прочие крестоизвращения не считаются.

#1153
10:54, 12 дек 2022

Panzerschrek[CN]
> А в чём их проблема? Что будет, если их переместить?
Это не потокобезопасно. Эти объекты предполагают, что к ним обращаются из разных потоков, а при перемещении меняется их адрес, а значит нужен второй слой синхронизаций, который защищает сам объект от изменения адреса объекта синхронизации.

Перемещение атомика - копирование его значения, но сам атомик меняет свой адрес в памяти.
Перемещение мютекса еще сложнее, в винде это критическая секция размером в 32 байта что-ли, не уверен что ее можно копировать, и это точно плохо, когда мютекс заблокирован.

#1154
11:04, 12 дек 2022

/A\
> а при перемещении меняется их адрес
А это уже детали реализации. Если нужен постоянный адрес, то можно объект в Box завернуть.

Крестоподход с неперемещаемым std::mutex - кривое говно, которое только вставляет палки в колёса.

Страницы: 176 77 78 7999 Следующая »
ФлеймФорумПроЭкты