Проектирование высокопроизводительной машины State в Java

Я начинаю писать библиотеку Java для создания высокопроизводительных конечных машин. Я знаю, что есть много библиотек, но я хочу писать свои собственные с нуля, так как почти все библиотеки там построили автоматики, оптимизированные для обработки только по одному.

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

Вопросы

  • Созданные автоматы обычно не массивные. (~ 100-500 состояний).
  • Реализация должна иметь возможность масштабировать.
  • Реализация должна включать быстрые преобразования (минимизация, детерминация и т.д.).
  • Глядя на внедрение DFA, NFA, GNFA, PDA и, возможно, Tree Automata. Надеюсь, под одним интерфейсом, если это возможно.
  • Должен иметь хороший баланс между использованием памяти и производительностью.

Текущие вопросы, касающиеся дизайна для меня на данный момент:

  • Должны ли быть определены классы для State, Symbol и Transition? Или должна быть использована "скрытая" внутренняя структура. Лично я чувствую, что использование классов как таковых будет тратить много памяти, поскольку одна и та же информация может храниться в гораздо более сжатой форме. Но позволяет ли это более быстрое преобразование? Имеет ли он какие-либо другие плюсы/минусы?

  • Каким будет наилучший способ хранения данных внутри? Использование структур данных, таких как HashMap и HashSet, позволяет отслеживать постоянный поиск по времени, но есть элемент накладных расходов. Это лучший способ? Сохранение информации о переходе в виде примитивного (или нет) массива, похоже, отнимает немало памяти. Особенно, когда библиотека должна обрабатывать множество автоматов одновременно. Каковы плюсы и минусы различных структур данных?

Я ценю любой вход. Спасибо!

Ответы

Ответ 1

Хорошо, как быстро вы это хотите? Код в файле brics.dk/automaton объявляет собственные классы состояния и перехода, очевидно, их можно было бы переписать с помощью примитивов (черт, все состояние класса перехода, по-видимому, легко поместилось бы на long).

Вещь, если вы перемещаете, например, класс Transition в просто примитив, то вы не должны больше использовать медленные коллекции HashMap<Transition,...> по умолчанию Java: вы можете использовать библиотеки, такие как Trove TLongObjectHashMap (или TLongInt... или TLongLong, что угодно), который владеет по умолчанию HashMap в больших количествах (библиотеки Trove в основном предоставляют карты и наборы, которые являются суперэффективными, быстрыми и малыми, когда вы работаете с примитивами: вы не генерируете бесчисленное количество мусора или постоянную ненужную упаковку вокруг примитивов, так что меньше GC и т.д. Если вы входите в производительность, то вы хотите проверить Trove... И их 3.0 предстоящий выпуск составляет 20% быстрее, чем Trove 2.0).

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

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

static int next_id;
.
.
.
id = next_id++;

и этот конструктор вызывается из... 90 разных мест!

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

Ответ 2

У меня есть несколько вопросов:

  • В какой части вам нужно быть быстрым, ввод FSA, создание FSA или выполнение FSA?

  • Откуда берется вход FSA? Человек вводит состояния и дуги, или какой-то автоматический процесс? Является ли реальный ввод исходным выражением, преобразованным в FSA?

  • Как часто меняется FSA? Раз в секунду? Один раз в год?

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

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