Обновить
4
0.2

Пользователь

Отправить сообщение

Наличие технической возможности и пользы довольно быстро создаст приложения, которые решают данную проблему прозрачно для пользователей. Webrtc, syncthing и прочие не на пустом месте появились.

Это я увидел. Выглядит в целом норм

Не знаю, где там Вы и что нашли. Но факт остаётся фактом: js хранит строки в utf-16, не в ucs-2.

Ну, два cast требуют переписывать сервера под потребителей. А так, можно сделать два call одновременно (да, через сырую отправку, увы). Тут даже noreply не нужен (если например вызовы к разным авторам, или если мы боремся с rtt).

Возможность селективного receive это очень важная фишка, которую многие акторные фреймворки забывают сделать, увы.

Ну, я же говорю, что это абсолютно нужно для реализации кастомных паттернов. Банальная задача: сделать два вызова сервера параллельно. В эрланге делается просто: отправляем два сообщения на запросы (call), после чего делаем два receive. А вот в модели трейтов, тут сложнее — нужно прыгать прям до основного ивент-лупа, там получать эти сообщения и дальше продолжать исполнение обработчика. Абсолютно лишняя сложность.

Не путайте, символы ("кодпоинты") и кодюниты. Длина в js выдаётся в кодюнитах, но храниться всё же utf-16. Просто одна из фишек utf-16, что он позволяет разрезать один кодпоинт на две суррогатных пары.

Ну, то есть линейная\mathcal{O}(n), так?

Правда ли что из-за backref-ов требует линейную память при декодировании? Аналогичный вопрос при кодировании (но там проще, т.к. можно поддерживать только для шейпов (если пользователю ок)).

Да, в том смысле, что на них можно просто прочекать весь мир. Но нет, потому что это практически неюзабельно.

Даже на взаимодействии двух акторов слишком часто приходиться закатывать солнце вручную. Я уже не говорю про всякие интересные правила типа "после того, как я получил сообщение W от актора X, я могу отправлять сообщение M всем авторам из группы G, но всего, не более чем 3 раза". Ну и там, по-хорошему, нужны линтипы для моделирования сообщений, которые можно отправить лишь некоторое количество раз.

Без линтипов, там нужно всех акторов запихивать в одну огромную монаду и трекать набор доступных сообщений в её типе. И то есть сложности...

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

Основная проблема в том, что Вы даже GenServer не сможете сделать без receive. Потому что GenServer.call должен сделать receive и получить ответ. Понятное дело, что можно зашить GenServer в ядро — но это не решает проблемы пользовательских паттернов взаимодействия (как сделать несколько параллельных вызовов генсерверов?;))

И нет, receive можно перенести в раст почти один в один как в эрланге. У меня был рабочий прототип (даже с пм по сообщениям) с семантикой эрланговских акторов. Всё никак не нахожу времени, чтобы довести его до ума.

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

Тестировать приватные хелеперы наоборот хорошо. Вот понадобилась Вам для реализации функция, которая хекс символ в число превращает. Пишете функцию(с кучей битовой магии), а рядом с ней тест.

Понадобится изменить реализацию и функцию выкинуть — ну выкинем тест и делов то.

Встроенные тесты хороши для тестирования вещей, которые модно было бы вынести в библиотеку, но лень/нет смысла.

Там — в типизации акторных систем.

Я понял, что акторы у Вас задаются трейтами. Но как уже сказал, это весьма неприятный способ задания акторов. Сравните с тем же send/receive в эрланге — там акторы это код.

Там проблема хуже. Набор сообщений, который автор готов обрабатывать динамически меняется со временем. При том, это буквально базовый функционал. Допустим актор A послал сообещние-запрос в автор B. Тогда после этого актор A умеет обрабатывать одно сообщение BReply — как только он его получит, он потеряет возможность обрабатывать сообщения BReply.

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

Ну, что делает это кеш нам не описали, поэтому ничего кроме рукомахательства я Вам не смогу сказать.

Основная идея в том, что вместо того чтобы создавать кучу маленьких списков, часто гораздо эффективнее будет создать один большой список. К этому списку обычно требуется также какая индексная структура данных, но это в среднем наоборот ускоряет код. Это нам немного ломает ооп-шные абстракции, но зато открывает путь к весьма интересным оптимизациям.

Наверное каноничным примером подобного преобразования является СНМ. В ней мы вместо того, чтобы хранить множества как отдельные структуры данных, складывается все множества в одну огромную структуру данных — но это даёт нам непревзойдённую эффективность объединения множеств почти за константу.

Если говорить из современных инкарнаций, то подобное преобразования можно найти в AoS -> SoA(struct of arrays), ecs и в целом в data-oriented programming.

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

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

Говоря о самой таксономии, мне кажется упущен один важный класс: native rmw. Этот класс включает в себя выполнение мутирующей операции за одну инструкцию. Например, атомарный инкремент часто компилируется в одну процессорную инструкцию. Хотя данный класс очень похож на 1-ый(cas-loop), он принципиально отличается отсутствием контеншена.

Last write wins

Вообще говоря так писать не очень хорошо. Поскольку у нас порядка между записями, то что такое "последняя запись" сказать сложно. Эта тонкая неоднозначность формулировок становится особенно видна когда появляются всякие visibility, ordering и happens before. Чуть корректнее говорить "some write wins".

P.S. В языках с gc ABA проблема почти никогда не возникает (разве что в интрузивных структурах данных — и то в каких-то патологических юзкейсах). Поэтому не очень понятно при чём здесь это.

P.P.S. CRDT это вообще не в ту степь. Они вообще не решают проблему мутации одного объекта — они рассматривают проблему мутации нескольких независимых копий. Поэтому кажется совсем не в тему (ну и тогда уже тащить также и OT, т.к. он гораздо чаще используется в рамках одного процесса).

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

Плюс здесь играют роль такие факторы:

  1. Незнание что быстрее вообще можно: "матрицы быстрее чем за N^3 умножать нельзя, куда там оптимизировать"...

  2. Закидывание ресурсами/серверами/подами. Особенно усугубилось с введением горизонтального масштабирования.

  3. Административным/бизнесовым запретом на отправку больших данных: "вы можете иметь не более 3 подписок"...

Поэтому, к сожалению, требуются очень хорошие процессы в плане тестирования и приёмки чтобы приобрести алгоритмическое мышление в рамках работы. Такое есть очень мало где.

Ну вот говорит говорит Вам нейронка: пиши здесь здесь два вложенных цикла. Вы возразите: "но это же O(n^2)!" А она Вам: всё будет работать быстро, там вложенный цикл выполняется редко. И как быть?

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

К сожалению, есть довольно много весьма простых и эффективных алгоритмов, которые, тем не менее, имеют очень сложные доказательства корректности и ещё более сложный анализ сложности. И без хорошей алгоритмической подготовки(а иногда и с ней) эти доказательства не прочитать даже.

Кажется ключевая проблема не совсем в списках. Подобного рода динамические массивы вообще не предназначены для подписей, которые в памяти занимают место, сопоставимое с объёмом всей памяти. Ну просто банально потому, что всякие List и Dictionary дают нам скорость и удобство ценой очень сильного потребления памяти.

Как только разбрасываться памятью становиться расточительно — необходимы другие подходы и структуры данных. Тут можно применять как точное предвыделение памяти (как нас заставляет делать тот же zig). Так и всякие векторные трансформации: часто лучше разместить все данные этого "кеша" в одном большом массиве, — это и код упростит(внезапно), и перф даст. Печально, правда, что про векторные представления очень редко говорят :(

А где здесь про олимпиадное программирование? Самое типичное стимулирование на "тяп-ляп и в продакшен" — здесь дело в менеджменте. Какой людям таргет поставишь — такой результат и получишь.

1
23 ...

Информация

В рейтинге
2 785-й
Зарегистрирован
Активность