Comments 16
Теперь понятно, зачем ему Lotus
На сколько я понимаю, при увеличении сложности вычислений, будет расти количество накладных расходов: либо из-за роста повторных вычислений в файберах, либо из-за роста количества оберток и их глубины. Данные файберы обеспечивают высокий FPS за счет принудительного ограничения времени итерации. В свою очередь накладные расходы, находясь в зависимости от сложности вычислений, неизбежно будут еще больше ограничивать время эффективных вычислений. И исходя из этой логики, должен существовать критический момент, когда произойдет зацикливание, так как все отведенное время уйдет на накладные расходы. Было бы интересно узнать, нигде ли я не ошибся? И если все верно, то производились ли подобные измерения падения производительности?
Пока я полагаю, что необходима осторожность при использовании такого подхода. Наверное, с повсеместным приходом Atomics и SharedArrayBuffer, когда параллелизм будет достигаться за ограниченное количество накладных расходов, файберы должны стать хорошим инструментом, для решения большого количества задач во фронт-энде.
Почитал стандарт по Atomics и SharedArrayBuffer, и похоже я пребывал в некотором заблуждении. Думал, что блокировку можно будет осуществлять, на уровне текущей операции event-loop, с перемещением ее в конец стека, и последующим восстановлением, собственно, как это происходит в упомянутом node-fibers. Но оказывается Atomics может блокировать только весь поток, и рассчитан для взаимодействия между процессами, что впрочем сейчас звучит логичнее, чем мое предположение.
Если же вы о том, что блуждая по куче кешей мы можем за квант не дойти до собственно полезного действия, то это не так. Как минимум одно полезное действие будет исполнено даже если оно не влезает в квант, что гарантирует прогресс. В этом случае, конечно, FPS начнёт уменьшаться, но это лучше, чем вообще ничего не делать. Но это относительно редкий кейс, возможный, например, при обработке больших массивов. Решается эта проблема просто — вместо одного цикла по большому массиву мы можем сделать два вложенных цикла, и вложенный заворачивать в файбер.
Например, вы не можете остановить всплытие ui-события из воркера, так как к моменту запуска обработчика, событие в UI-потоке уже завершит свой жизненный цикл.
— можно, но не для всех. github.com/lifeart/async-event
Также, даже «обычные» модели с 60 Гц могут поддерживать динамическую частоту обновления (FreeSync, G-Sync...). Какой статус её поддержки браузерами, лично не тестил, но похоже, что её пока толком нет.
Покажите реальный пример, «было» и «стало», чтобы можно было оценить «когнитивные издержки» программиста, которых он избежал, воспользовавшись вашей библиотекой вместо ручного написания конечного автомата. (Пример реактового механизма как раз показателен, они не делали универсальных файберов, они ограничились конкретной задачей — асинхронной отрисовкой дерева компонентов. И это кажется вполне разумным.)
В экосистеме реакта для модельного слоя, кстати, есть редакс-сага, там тоже «асинхронные квантифицируемые и отменяемые процессы вычислений», только они квантифицируются механизмом генераторов. Не думали о подобном дизайне своей библиотеки? Ну и там уже до RxJS рукой подать, чтобы начать управлять потоками вычислений «по-взрослому» :).
Понимание, что делаешь, нужно всегда. Вручную управлять промежуточными данными не нужно. Конечного автомата никакого нет, есть только кеши. Реальный пример "было-стало" подробно рассмотрен в докладе. Можете переписать его на конечных автоматах, если считаете, что это проще, чем завернуть несколько функций в обёртки. Не нашёл в документации по сагам ничего про квантизацию. Я не хочу вручную управлять потоками вычислений, я хочу задавать инварианты и чтобы рантайм самостоятельно позаботился об их эффективном поддержании.
Я не хочу вручную управлять потоками вычислений, я хочу задавать инварианты и чтобы рантайм самостоятельно позаботился об их эффективном поддержании.
А мне казалось, что вы хотите разбить монолитный и синхронный вычислительный процесс на асинхронные кусочки, чтобы эксклюзивно не занимать ресурсы процессора (эта тема в обобщённом виде называется «кооперативная многозадачность»). И показалось, что надстраивать над этим такой сложный рантайм — оверинженеринг.
Для затравки в статье был приведен пример:
import { $mol_fiber_async , $mol_fiber_start } from 'mol_fiber/web'
const one = ()=> $mol_fiber_async( back => setTimeout( back ) )
const two = ()=> one() + 1
const three = ()=> two() + 1
const four = ()=> three() + 1
$mol_fiber_start( four )
Но далее в описании работы нигде подобный сценарий не упоминался. Вместо этого каждая вызываемая функция явно оборачивается в $mol_fiber_func. Я что-то упустил? Возможно ли с помощью $mol_fiber реализовать код из примера выше?
Разумеется, вы можете использовать любые возможности яваскрипта.
А как это работает? Если one() возвращает фибер, а two() использует это возвращенное значение синхронно.
Ни одна из этих функций не возвращает файбер. Файберы создаются под капотом. one
при первом вызове бросает Promise
и останавливает всё вычисление, начатое в $mol_fiber_start
. Когда промис резолвится, вычисление перезапускается, но на этот раз one
возвращает число (в данном случае — число прошедших миллисекунд, передаваемое setTimeout
).
Quantum Mechanics of Calculations in JS