Pull to refresh

Comments 16

Честно-честно не для этого. А по поводу Смол — сижу вот как раз тыкаю в него :)

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


Пока я полагаю, что необходима осторожность при использовании такого подхода. Наверное, с повсеместным приходом Atomics и SharedArrayBuffer, когда параллелизм будет достигаться за ограниченное количество накладных расходов, файберы должны стать хорошим инструментом, для решения большого количества задач во фронт-энде.

Почитал стандарт по Atomics и SharedArrayBuffer, и похоже я пребывал в некотором заблуждении. Думал, что блокировку можно будет осуществлять, на уровне текущей операции event-loop, с перемещением ее в конец стека, и последующим восстановлением, собственно, как это происходит в упомянутом node-fibers. Но оказывается Atomics может блокировать только весь поток, и рассчитан для взаимодействия между процессами, что впрочем сейчас звучит логичнее, чем мое предположение.

Всё зависит от того как «заворачивать». Можно завернуть всё вычисление в один файбер и тогда никакого квантования не будет. Можно завернуть каждую элементарную операцию и тогда накладные расходы на файберы многократное превысят полезное действие. Соответственно оптимум находится где-то посередине. Заворачивать нужно неидемпоентные операции и операции, которые могут потребовать ресурсов существенно больше, чем накладные расходы на файбер.

Если же вы о том, что блуждая по куче кешей мы можем за квант не дойти до собственно полезного действия, то это не так. Как минимум одно полезное действие будет исполнено даже если оно не влезает в квант, что гарантирует прогресс. В этом случае, конечно, FPS начнёт уменьшаться, но это лучше, чем вообще ничего не делать. Но это относительно редкий кейс, возможный, например, при обработке больших массивов. Решается эта проблема просто — вместо одного цикла по большому массиву мы можем сделать два вложенных цикла, и вложенный заворачивать в файбер.
Например, вы не можете остановить всплытие ui-события из воркера, так как к моменту запуска обработчика, событие в UI-потоке уже завершит свой жизненный цикл.

— можно, но не для всех. github.com/lifeart/async-event
Там событие сразу принудительно останавливается, а отложенно уже кидается новое такое же. К сожалению такой хак прокатит далеко не всегда.
Читая про привязку к 60 кадрам в секунду, хочется напомнить, что не все клиенты используют такую частоту обновления экрана. Сейчас всё больше появляется мониторов с частотой 75, 100, 144 Гц. Насколько понимаю, современные браузеры стараются обновлять картинку синхронно с обновлениями экрана и у них зачастую получается поддерживать такие частоты.

Также, даже «обычные» модели с 60 Гц могут поддерживать динамическую частоту обновления (FreeSync, G-Sync...). Какой статус её поддержки браузерами, лично не тестил, но похоже, что её пока толком нет.
Выглядит бесполезной библиотека, т.к. в любом случае «квантификация» процесса вычислений потребует от программиста понимания, что он квантифицирует, и, в общем-то, ручного управления промежуточными данными. Проще сразу написать конечный автомат для своих вычислений, чем притворяться, будто его нет, оборачивая код в магические функции (с дикими расходами на «универсальную» мемоизацию).

Покажите реальный пример, «было» и «стало», чтобы можно было оценить «когнитивные издержки» программиста, которых он избежал, воспользовавшись вашей библиотекой вместо ручного написания конечного автомата. (Пример реактового механизма как раз показателен, они не делали универсальных файберов, они ограничились конкретной задачей — асинхронной отрисовкой дерева компонентов. И это кажется вполне разумным.)

В экосистеме реакта для модельного слоя, кстати, есть редакс-сага, там тоже «асинхронные квантифицируемые и отменяемые процессы вычислений», только они квантифицируются механизмом генераторов. Не думали о подобном дизайне своей библиотеки? Ну и там уже до RxJS рукой подать, чтобы начать управлять потоками вычислений «по-взрослому» :).

Понимание, что делаешь, нужно всегда. Вручную управлять промежуточными данными не нужно. Конечного автомата никакого нет, есть только кеши. Реальный пример "было-стало" подробно рассмотрен в докладе. Можете переписать его на конечных автоматах, если считаете, что это проще, чем завернуть несколько функций в обёртки. Не нашёл в документации по сагам ничего про квантизацию. Я не хочу вручную управлять потоками вычислений, я хочу задавать инварианты и чтобы рантайм самостоятельно позаботился об их эффективном поддержании.

Я не хочу вручную управлять потоками вычислений, я хочу задавать инварианты и чтобы рантайм самостоятельно позаботился об их эффективном поддержании.

А мне казалось, что вы хотите разбить монолитный и синхронный вычислительный процесс на асинхронные кусочки, чтобы эксклюзивно не занимать ресурсы процессора (эта тема в обобщённом виде называется «кооперативная многозадачность»). И показалось, что надстраивать над этим такой сложный рантайм — оверинженеринг.
А давайте не будем заниматься словесной эквилибристикой? Эта цитата касалась 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).

Sign up to leave a comment.

Articles