Скорость конечных автоматов - ОО против процедурных - PullRequest
4 голосов
/ 30 сентября 2010

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

Пока что использование машины, добавление новых состояний и т. П. Оказалось простым и не очень сложным. Легко понять и уйти на месяц, и возвращение к коду не будет очень дезориентирующим. Однако я не уверен, какова скорость компромисса с текущим подходом ОО. Удалит ли размещение объектов, хранение данных и т. Д. Большую часть скорости, которую можно было бы получить, используя набор меток и goto операторов?

Ответы [ 4 ]

3 голосов
/ 30 сентября 2010

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

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

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

Дополнительная мысль: можете ли вы просто потратить еще 5000 долларов на более качественное оборудование, чтобы избежать оптимизации затрат на разработку на 50 000 долларов?

3 голосов
/ 30 сентября 2010

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

2 голосов
/ 30 сентября 2010

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

Быть более умеренно более техническим: процессор имеет 32-64 КБ кэша L1 и от нескольких до пары десятков мегабайта L2-L3.Кэши веток составляют максимум несколько килобайт.

1 голос
/ 30 сентября 2010

Как часто меняется конечный автомат?Если оно какое-то время остается постоянным, я перевожу его в жестко запрограммированную подпрограмму на любом языке, который я предпочитаю.

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

Затем я либо просто создаю эту часть приложения, либо динамически компилирую и связываю ее с dll и динамически загружаю ее.Последнее занимает всего пару секунд.

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

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


Просто чтобы показать вам, что я имею в виду, рассмотрим регулярное выражение для десятичных целых чисел:

dd*

где «d» означает цифру.В качестве конечного автомата (кортежей) это будет:

A d -> B
B d -> B

как код:

char c = getc();
if (DIGIT(c)){
  c = getc();
  while(DIGIT(c)){
    c = getc();
  }
}

Видите сходство этого кода с регулярным выражением?Не думайте о c = getc() как о «получить следующий символ с».Думайте об этом как «принять текущий символ с».Я надеюсь, что вы видите, что код не может стать намного быстрее, чем этот.

Если вы действительно начинаете с набора дуг, вы можете сгенерировать это:

c = getc();

A:
if (DIGIT(c)){c = getc(); goto B;}
goto END;

B:
if (DIGIT(c)){c = getc(); goto B;}
goto END;

END:

, которыйэто код спагетти, но не больше, чем набор дуг, и он будет таким же быстрым, как и структурированный код.(Фактически, это более или менее то, во что компилятор преобразует ваш структурированный код.)

...