Статьи

ООП и Производительность

Объектно-ориентированное программирование, по сравнению с процедурным , обычно рассматривается как компромисс: повышенная «производительность разработчика» за счет лучшей модульности / повторного использования по сравнению с более медленной обработкой, основанной на введении дополнительных служебных объектов поиска во время выполнения (по сравнению с эквивалентным набором функций + переменные).

Поищите в Google «php oop», и это первый результат , который довольно хорошо сбалансирован, но приходит к безопасному заключению;

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

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

Имея в виду, что я говорю только в общем смысле, я думаю, что в процедурном коде существует тенденция использовать «грубую силу» — реальное значение и поведение логики, маскируемой спагетти. Если то, что на самом деле делал код, было прозрачно для разработчика, они могли бы увидеть некоторые из «слепых» недостатков, которые они представили.

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

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

$giantDataSet = getGiantDatasetFromSomewhere(); $totalX = calculateTotalX($giantDataSet); $averageX = calculateAvergageX($giantDataSet); $totalY = calculateTotalY($giantDataSet); $averageY = calculateAverageY($giantDataSet); // etc. 

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

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

Модифицированная версия стала чем-то вроде этого, выполнив полный анализ одного цикла;

class Analyser { // stuff here... // Process the data something like this... function analyse($data) { foreach ( $data as $row ) { foreach ( array_keys($this->filters) as $key ) { $this->filters[$key]->filter($row); } } } } // Usage something like this; $A = & new Analyser(); $A->addFilter(new TotalXFilter()); $A->addFilter(new AverageXFilter()); $A->addFilter(new TotalYFilter()); $A->addFilter(new AverageYFilter()); $A->analyse(getGiantDatasetFromSomewhere());
class Analyser { // stuff here... // Process the data something like this... function analyse($data) { foreach ( $data as $row ) { foreach ( array_keys($this->filters) as $key ) { $this->filters[$key]->filter($row); } } } } // Usage something like this; $A = & new Analyser(); $A->addFilter(new TotalXFilter()); $A->addFilter(new AverageXFilter()); $A->addFilter(new TotalYFilter()); $A->addFilter(new AverageYFilter()); $A->analyse(getGiantDatasetFromSomewhere()); 

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

Я в основном начал искать то, что нужно для того, чтобы парсер Dokuwiki мог обрабатывать текст в кодировке UTF-8. Теперь я более или менее переписал синтаксический анализатор, используя лексер из Simple Test (на самом деле, слегка измененную версию, учитывающую UTF-8).

Короче говоря, лексер Simple Test выступает в качестве инструмента, облегчающего управление регулярными выражениями — вместо гигантских регулярных выражений вы пишете много маленьких / простых. Лексер позаботится об их эффективном объединении, а затем предоставит вам SAX-подобный API обратного вызова, который позволит вам писать код, отвечающий на совпадающие «события».

Для меня неожиданным результатом стало резкое увеличение производительности. Разбор источника синтаксиса wiki: с помощью собственного синтаксического анализатора Dokuwiki, на моем компьютере, занимает от 5 до 7 секунд. Использование синтаксического анализатора, основанного на лексере Simple Test, занимает от 0,2 до 0,25 секунды.

Кажется, причиной этого является то, что парсер Dokuwiki сканирует полный необработанный текст несколько раз, заменяя синтаксис вики HTML. По всему исходному документу происходит не менее 18 сканирований. В то же время Lexer от Simple Test сканирует весь документ только один раз.

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

Продолжая обсуждение разбора дальше, похоже, похожая история рассказана Пикколо ;

Piccolo — это небольшой, чрезвычайно быстрый парсер XML для Java

Piccolo был разработан с использованием модифицированных версий инструментов генератора синтаксических анализаторов JFlex и BYACC / J… Я заметил, что почти все синтаксические анализаторы Java XML написаны от руки

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

В любом случае — возвращаясь к анализатору Dokuwiki, еще есть над чем поработать.

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

Мне также нужно проверить, что он действительно обрабатывает UTF-8: на данный момент я добавил модификатор / u к вызову preg_match (), который он делает, но там также есть некоторое использование функций str * для извлечения подстрок — я может быть в состоянии обойти это, используя preg_split () и модификатор / u.

Все должно идти хорошо, хотя, кроме производительности, еще одним положительным результатом будет то, что выходной формат хорошо отделен от синтаксического анализа. Это означает, что должна быть возможность отображать альтернативные выходные форматы из текущего HTML — «просто» подключая класс, содержащий правильные имена методов — что-то вроде;

class Plaintext_Renderer { var $indent = 0; // Called on dokuwiki headers function header($level, $text) { $this->indent = $level; // Never mind the UTF-8... fwrite(STDOUT, strtoupper($text)); } // Normal text function cdata($text) { fwrite( STDOUT, str_pad($text, $this->indent, " ", STR_PAD_LEFT) ); } // etc. }
class Plaintext_Renderer { var $indent = 0; // Called on dokuwiki headers function header($level, $text) { $this->indent = $level; // Never mind the UTF-8... fwrite(STDOUT, strtoupper($text)); } // Normal text function cdata($text) { fwrite( STDOUT, str_pad($text, $this->indent, " ", STR_PAD_LEFT) ); } // etc. } 

И хорошим совпадением является то, что в Википедии используется почти та же самая разметка, что и в «Докувики» (я полагаю, что «Докувики» частично основан на «МедиаВики»).

Источник (в процессе и не большой) здесь вместе с тестами .