Комментарии 5
Статья понравилась - красивое оформление, без лишнего, и видно много ручной работы, а не просто нейрослоп.
"оценивать компромиссы отдельно: расход памяти, стоимость удаления, порядок элементов и обход" - как правило в реальных проектах это экономия на спичках, разные форматы хранения графов и производительность обхода влияют очень незначительно. Условно один медленный api-запрос или неоптимизированный компонент могут затормозить рендеринг и съесть памяти намного больше, чем большой граф. Поэтому если используется достаточно популярная система реактивности, можно не думать о таких нюансах, но в теории знать полезно.
Что там с локальным кэшем
O(алгоритм) <->O(память) особенно при наличии рекурсии содержащей неявный стек
Хеширование и всякие хитрости с двоично-десятичными значениями отданными на усмотрение компилятору (наподобие 256 Integer Cache Optimization у Питона)
Локальные или условно-глобальные переменные отданные на усмотрение компилятора особенно при многопоточке, по-разному аллоцируемые кучи в зависимости от контекста
Неявное копирование данных при наличии всяких им- или мутабельных объектов или "случайно" занесённых с внешней структурой даже в простые описания
Вот смотрю я на это все и вспоминаю свои мысли на тему подобных пепелацев. На странице очень ограничено число реальных данных и элементов управления - буквально десятки, и все фреймворки супер круто такое обслуживают из коробки. И когда я столкнулся бы с такими проблемами - я бы старался оглянуться и понять что что то таки делается не так. Если на одну кнопку есть десяток классов и куча реактивно-функционального кода в котором ломаются зубы фреймворка, разраба и браузера, а цена поддержки превышает ручное создание всех версий страницы - то пора бы уже охладить подходы и более просто писать код отказавшись от реактивных космолетов там где велосипеда за глаза
В $mol_wire используется один массив вместо 4 в Solid. Это даёт всего 64 байта на узел графа состояний и 16 байт на связь между ними. Всё это с учётом сжатия ссылок. Подробнее тут: https://mol.hyoo.ru/#!section=docs/=tfhz4w_v33vsu
Нейросеть вас такому не научит.
Отдельно ценно, что вы не стали прятать разброс между конфигурациями V8 — именно на этом месте обычно рождается миф «массив всегда быстрее списка». По вашим же цифрам видно, что разницу между Node 22 и Node 24 (112 против 320 байт медианного расстояния) скорее даёт не структура, а момент промоушена Subscription в старое поколение: при --max-size-semi-space 8 и 32 МБ объекты переселяются в разные моменты, и внутри измеряемого цикла меняется ещё и число скавенджей. Это разводится без большого стенда: построить граф до замера, вызвать gc() под --expose-gc, прогнать обход и отдельно снять --trace-gc (сколько скавенджей и промоушенов на итерацию). Если после вычитания GC-времени разрыв между массивами и интрузивным списком сократится, значит в замере обхода вы измеряли в основном работу молодого поколения, а не локальность данных. Вопрос: пробовали ли такой контроль с прогревом и явным gc() перед циклом — и устоял ли после него вывод про 4 мс на массовом удалении?

Почему O(1) не гарантирует высокую скорость: четыре структуры данных для графа signal – effect