Самые быстрые настройки для PHP-скриптов

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

    Так как серверные PHP-скрипты выполняются, бывает, много раз в секунду, скорость загрузки конфигов — достаточно важный параметр. Хотя ему, порой, уделяется не очень много внимания. Давайте сравним различные варианты хранения настроек для PHP-скриптов с точки зрения скорости их работы. Ну и коснемся вкратце их удобства.

    Итак, подопытные:
    • INI-файлы
    • PHP-скрипты
    • XML-файлы
    • Текстовые файлы
    • Файлы с сериализованными данными
    • Вне конкурса — PHP-скрипты с define'ами
    • JSON-файлы NEW!
    Чтобы никого не обидеть, перечисление в алфавитном порядке. Вариант хранения настроек в базе данных, кстати, не рассматривался. Уж слишком невыгодным он выглядит с точки зрения скорости доступа к настройкам.

    Условия:
    • Как можно быстрее загрузить настройки из файла
    • Вернуть массив настроек в виде «ключ» => «значение»
    • Конфигурационный файл содержит 10, 100 или 1000 конфигурационных параметров, представляющих собой короткие строки
    • Конфигурация читается 1000 раз подряд, замеряется время работы в секундах
    Понятно, что со вторым из условий тестирования можно поспорить. Мне этот вариант показался оптимальным для хранения настроек в памяти во время работы скрипта, но в некоторых случаях он таковым не является. И, кстати, этому условию не удовлетворяют PHP-скрипты с define'ами, из-за чего они и были помечены «вне конкурса».

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

    Правда, необходимо сделать небольшое уточнение по поводу программного обеспечения сервера. Использовался реальный веб-сервер, в момент низкой загрузки. Соответственно, конфигурация сервера «боевая»: Linux Debian Lenny, много памяти и RAID1-массив жестких дисков. PHP серии 5.2.x (не самый последний, врочем) с eAccelerator'ом. На время тестов отключался Zend Optimizer, чтобы тесты были более «чистыми», что минимально повлияло на результаты. Тесты без eAccelerator тоже проводились, но, как ни странно, сильно на распределение сил это не повлияло. Причина, на мой взгляд, кроется в том, что eAccelerator настроен на дисковое кэширование опкодов PHP и на сравнение времени модификации файлов, что «съедает» определенное количество времени — хотя и приносит определенные бонусы.

    INI-файлы


    Результаты: 0.015, 0.086, 0.784

    Пример:
    x1 = 1
    x2 = 2
    x3 = 3

    Скрипт:
    function config($file) {
        return parse_ini_file($file);
    }

    Конфигурационный файл с классическим, всем знакомым синтаксисом. Достаточно быстрый и удобный способ.

    PHP-скрипты


    Результаты: 0.029, 0.111, 0.902

    Пример:
    <?
    return array (
      'x1' => '1',
      'x2' => '2',
      'x3' => '3',
    );
    ?>

    Скрипт:
    function config($file) {
        return include($file);
    }

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

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

    XML-файлы


    Результаты: 0.062, 0.385, 3.911

    Пример:
    <root>
      <x1>1</x1>
      <x2>2</x2>
      <x3>3</x3>
    </root>

    Скрипт:
    function config($file) {
        $r = array();
        $dom = new DOMDocument;
        $dom->load($file);
        foreach ($dom->firstChild->childNodes as $node) {
            if ($node->nodeType == XML_ELEMENT_NODE) {
                $r[$node->nodeName] = $node->firstChild->nodeValue;
            }
        }
        return $r;
    }

    Недостаток очевидный: очень маленькая скорость работы, в несколько раз медленнее, чем другие варианты. Чтобы проверить, не слишком ли медленная PHP-часть этого кода, я попробовал сделать return сразу после загрузки XML-документа (то есть, фактически, конфигурационные параметры не возвращались). Это ускорило процесс всего приблизительно в два раза. Что подтвердило общий вывод.

    Результаты: NEW! 0.047, 0.276, 2.791

    Скрипт: NEW!
    function config($file) {
        $r = array();
        foreach(simplexml_load_file($file) as $k => $v) {
            $r[$key] = strval($v);
        }
        return $r;
    }

    С помощью SimpleXML получается, конечно, быстрее. Но не настолько, чтобы претендовать на лидерство.

    Текстовые файлы


    Результаты: 0.034, 0.250, 2.369

    Пример:
    x1  1
    x2  2
    x3  3

    Скрипт:
    function config($file) {
        $r = array();
        if ($F = fopen($file, "r")) {
            while (($line = fgets($F)) !== false) {
                list($k, $v) = explode("\t", $line, 2);
                $r[trim($k)] = trim($v);
            }
            fclose($F);
        }
        return $r;
    }

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

    Результат: NEW! 0.036, 0.250, 2.213

    Скрипт: NEW!
    function config($file) {
        $r = array();
        foreach (explode("\n", file_get_contents($file)) as $line) {
            list($k, $v) = explode("\t", $line, 2);
            $r[trim($k)] = trim($v);
        }
        return $r;
    }

    Такой вариант реализации несколько медленнее для небольших файлов и быстрее для больших файлов. Но, в общем, не влияет на расстановку сил.

    Файлы с сериализованными данными


    Результаты: 0.011, 0.041, 0.309

    Пример:
    a:3:{s:2:"x1";s:1:"1";s:2:"x2";s:1:"2";s:2:"x3";s:1:"3";}

    Скрипт:
    function config($file) {
        return unserialize(file_get_contents($file));
    }

    Наименее удобочитаемый конфигурационный файл — но при этом самый быстрый результат.

    PHP-скрипты с define'ами


    Результаты: 0.045, 0.252, 2.404

    Пример:
    <?
    define("x1", "1");
    define("x2", "2");
    define("x3", "3");
    ?>

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

    JSON-файлы NEW!


    Результаты: 0.015, 0.057, 0.495

    Пример:
    {"x1":"1","x2":"2","x3":"3"}

    Скрипт:
    function config($file) {
        return json_decode(file_get_contents($file), true);
    }

    JSON ворвался в нашу жизнь. Его реализация в PHP позволила даже обогнать одного из лидеров, INI-файлы, но немного уступает встроенной сериализации PHP. Одно замечание: приведенный код возвращает не массив, а stdClass object.

    Выводы


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

    Если Вы серьезный человек — то избегайте прямого чтения текстовых файлов, особенно с большими объемами. Вместо этого Вам вполне подойдут JSON-файлы или INI-файлы, тем более, что скрипты станут работать быстрее.

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

    Настройки в формате XML — самые медленные. Прежде, чем их использовать, подумайте хорошенько.

    Искренне надеюсь, что define'ы никто не использует, поэтому оставляем их обсуждение вне выводов.

    Итог


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

    Результаты: 0.018, 0.046, 0.317

    Оптимально с точки зрения гибкости и скорости, на мой взгляд.

    А вот и сам скрипт:
    function config($file) {
        $file_dat = "$file.dat";
        if (!file_exists($file_dat) || filemtime($file_dat) <= filemtime($file)) {
            $r = include($file);
            if ($F = fopen($file_dat, "w")) {
                fwrite($F, serialize($r));
                fclose($F);
            }
        } else {
            $r = unserialize(file_get_contents($file_dat));
        }
        return $r;
    }

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

    P.S. PHP-код в статье не самый хороший. Я писал его, преследуя две цели: краткость и скорость работы. Поэтому отсутствуют комментарии, длинные имена переменных и различные проверки. Кроме того, большая часть кода работает под PHP 4 и 5 без проблем (кроме, конечно, XML). Надеюсь, это не вызовет излишнего накала страстей.
    P.P.S. В сравнение добавлен код JSON.
    P.P.P.S. Добавлены небольшие ремарки по поводу железа и программного обеспечения. Без них, согласен с авторами комментариев, было как-то не так.
    Ads
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More

    Comments 192

      +9
      К своему стыду ни разу не задавался вопросами подобной оптимизации и был приятно удивлен скоростью парсинга INI-файлов! Спасибо за сравнения, заставили задуматься :)
        +1
        Ну правильно, в случае парсинга ini файлов или же json'а вызываются Cшные функции, они всяко быстрее реализаций на чистом php
          0
          Если считаете, что уже достаточно овладели PHP, поизучайте язык более низкого уровня (C / Pascal), чтобы понимать как оно работает и подобными вещами вас будет уже не удивить ;)
            +6
            Ну Си — да, а вот паскаль вряд ли поможет (:
              +4
              Pascal may be an admirable language for teaching beginners how to program

              Это сказал некто Керниган.

              Некто Дональд Кнут в 2000 году сам портировал TeX на Pascal — как думаете, с чего бы?

              Не нужно оголтело равнять Pascal = Delphi’s VCL и делать поспешные выводы.
                0
                Для обучения новичков программированию Паскаль хорош. Потому что начинать с Си очень трудно. Но для того, чтобы понимать как работает PHP на более низком уровне знания Паскаля вряд ли помогут.
                  –1
                  В цитате главное слово — «how».

                  Вы хотите поговорить, как работает PHP на низком уровне? — Тогда нужно сначала попрограммировать на C/C++, а потом заглядывать в код функций PHP (а не программировать на PHP непосредственно).

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

                  Если вернуться к паскалю — гляньте на оператор «^». Или вообще на спецификацию посмотрите. А то на «низком» уровне все программировать научились, а смысл термина как-то стерся.
                    –1
                    функции store_config/load_config — это уже не уровень языка, это более высокий уровень абстракции — фреймворки, etc, потому что config — это само по себе абстрактное понятие в отличие от xml, ini или что там еще.
                    А насчет паскаля — насколько я его помню, указатели в нем не настолько «продвинуты», как в Си. Поправьте меня, если я не прав.
                      0
                      ага, более. но никто не мешает делать все базовые вещи с указателями и в паскале. хотя конечно после С паскаль вспоминаешь как тихий ужас в этом плане.
                        0
                        а указатели на функции в нем есть? гугл так и не дал внятного ответа.
                          0
                          честно говоря лет 10 минимум уже не прикасался к паскалю. и тогда когда использовал, то не чистый паскаль был, а «дельфи». там была возможность.
            0
            Одна из первых заповедей оптимизации — используй native функции (если такая есть конечно). Они всегда быстрее. Альшанецкий говорил что в его практике только один раз кастомное решение на чистом PHP было быстрее нативной функции, а это о чем-то да говорит )
              +7
              Говорит о том, что нативная функция кривая, очевидно же.
                0
                DevConf 2010?
                  0
                  Так точно )
                0
                Стоит заметить, что внешние файлы с настройками должны быть в закрытой папке, либо на уровень выше www.
                  0
                  В случае конфигов на PHP это не обязательно. Даже если злоумышленник найдет config.php и откроет его через браузер, он увидит пустую страничку.
                  Кроме этого, доступ к конфигам можно ограничивать через настройки сервера (как вариант, .htaccess).
                  Но, в сущности, Вы правы — защищать конфиги — первое дело каждого программиста.
                    +7
                    >В случае конфигов на PHP это не обязательно.

                    все так говорят, пока глюканувший сервер не начнет отдавать исходники скриптов :)
                  0
                  Когда начал читать, то тоже подумал, что INI будут хуже обычного PHP-файла с массивом. А оно вон как повернулось.
                  +11
                  Прочитав статью меня чуть кондрашка не схватила…
                  Чтение сериализованного массива из файла и его последующая ансериализация быстрее чтения переменных из php-файла…

                  Сериализованные массивы в файлах эффективны, если ими можно заменить данные из БД.
                    +5
                    Ваша кондрашка умеет читать? ;)
                      +1
                      Это Кондрашка им. Чехова.
                      • UFO just landed and posted this here
                          +1
                          Нет, мимо станции проезжать умеет))
                            0
                            Мимо станции умеет проезжать Шляпа™ им. Чехова, вы что-то путаете :-)
                      +3
                      Парсить сериализованный массив менее ресурсоёмко, чем парсить php-код. Всё верно.
                        0
                        А на доступ к файлу смотреть не нужно, так как он имеет место в обоих случаях.
                          +2
                          Но если php-код уже пропарсен php-акселератором, тогда его просто нужно выполнить.
                          Жаль не проверяли
                            0
                            Самое интересное, что всю жизнь считал, что php-код будет как раз-таки быстрее, и кешировал ini-файлы в php-код. Теперь-то буду знать, что эти усилия никому, оказывается, не нужны.
                              0
                              Настройки лучше кешировать в памяти.
                          +2
                          А сколько раз проводился каждый тест?
                            +2
                            1000 последовательных запусков для каждого из алгоритмов.
                            Все тесты вместе перезапускал несколько десятков раз, чтобы проверить, что загрузка сервера не влияет на результаты. Результаты по времени между запусками отличались на незначимую величину :-)
                            +4
                            Эцсамое, а нельзя подгрузить весь «тяжёлый» хлам, а потом схоронить где-нибудь в memcache в сериализованном виде?
                              +2
                              Тоже самое подумал. Хранить конфиги надо там где удобно (база, ini или xml файлы, главное не define'ами ;)), и при проблемах с производительностью просто кэшировать их. Хоть в мемкэш, хоть даже в файлы в сериализованном виде. Будет и быстро и удобно.
                                +1
                                а чем так плохи defin'ы, можно поподробней?
                                  +1
                                  Навскидку: глобальное пространство имен, невозможность переопределить.
                                    +2
                                    Если в двух словах, то:
                                    • Они медленные
                                    • Они глобальные. Если переменные можно сделать локальными (включить определение переменных в теле функции, например), то константы — нет
                                    • Они ужасные: include(PROJECT_ROOT. "/lib/class.php") vs include("$project_root/lib/class.php")
                                      +3
                                      насчет медленных согласен, внешний вид это субъективно, а вот глобальность — почему это плохо?
                                      если речь идет о глобальном конфиге сайта
                                      почему это хуже чем например делать
                                      $cfg = config::getInstance();
                                      в каждом месте где нужно узнать project_root?

                                      я прошу прощения за возможное ламерство, просто хочу восполнить пробел в понимании, пользуясь моментом :)
                                        +1
                                        Глобальность это всегда плохо, а вместе с невозможностью переопределения ведет к сильному связыванию и жесткой архитектуре. Даже с синглтонами можно манипулировать конфигами (пример синтетический):

                                        config->switchInstance('additional');
                                        runMethod();
                                        config->switchInstance('main');
                                        
                                        function runMethod(){
                                            $cfg = config::getInstance();
                                            ...
                                        }
                                        
                                          0
                                          Вы в чем-то правы.
                                          Но большинство реализаций с константами выглядят примерно так (схема главного скрипта):

                                          include конфиг;
                                          include классы x 10;
                                          include коннект к базе данных;

                                          константы при этом встречаются только в инклюдах в главном скрипте и в коннекте к базе данных. Вопрос: а смысл было их делать глобальными?

                                          Хотя реализации, повторю, могут отличаться
                                        +2
                                        Невозможность определять массивы, объекты.
                                      +4
                                      У меня только один вопрос — настройки подключения к memcache где хранить? :-)
                                      +4
                                      Логичнее всего сохранять такую инфу в apc. 0.002 0.015 0.17
                                        0
                                        Интересно, но обычными инклудами получилось 0.08 против 0.17
                                        Есть над чем задуматься
                                          +1
                                          Смысла в ваших цифрах нет, железо и тестовые данные у вас с автором разное.
                                          Выкладывайте тогда результаты всех тестов (txt, ini, xml, ...).
                                        +4
                                        Какая библиотека использовалась для кеширования опкода?
                                          +3
                                          Важное уточнение. PHP 5.2.x + eAccelerator 0.9.6.x
                                            0
                                            А ОС?
                                              +2
                                              Linux Debian Lenny

                                              Если интересно, то
                                              Intel Core2Duo 3000 GHz
                                              Memory 4GB 800 MHz
                                              2x Western Digital RE3 RAID1
                                                +1
                                                Убедили :)
                                                Просто если бы вы не использовали опкод кешер, или проводили тесты в Виндовсе, это сильно сказалось бы на времени подключения файлов.
                                          +1
                                          Практический подход к оптимизации (на базе опытов).

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

                                          Я не могу сейчас уже привести примеры кода, но могу описать ситуацию, когда экономил на выводе больших массивов данных из базы. Удобно, например, при выводе детализаций по всякого рода аккаунтингу (трафик, звонки, смс и прочие тарифицируемые...). Такие данные характерны короткими справочниками с десятками записей и огромной таблицей CDR (собственно записей тарификации). Вот в таких ситуациях, чтение справочников целиком из базы в массив в памяти и использование этих массивов при выводе с одним простым запросом только к таблице CDR в базе, позволяется «разогнать» скрипт в сотни раз, по сравнению с решением в лоб — запросами с join-ами в базу данных.

                                          Конечно, это скорее оптимизация СУБД, но средствами языка программирования. :)
                                            0
                                            А все-таки стоит проверить хранение конфигов в базе данных. Да, конфиги в базе данных сильно проигрывают в скорости на указанных вами условиях работы. Но стоит рассмотреть другие варианты: чтение 20 настроек при определенных 1000, сохранение настроек.
                                              +3
                                              а хранить настройки подсоединения к БД? тоже в БД?
                                                0
                                                Настройки подсоединения к БД можно ужать до одной строки (e.g. 'mysql://user:password@host:port'), где её хранить — некритично.
                                                0
                                                А БД бывают разные, к примеру, SQLite, которому только путь до БД нужен по сути.
                                              0
                                              В ваших примерах используются разные функции для чтения файлов. Мне кажется это тоже повлияло на результат исследования.
                                                0
                                                Старался по минимуму использовать PHP-wrapper'ы для работы с файлами, только там, где это действительно необходимо. А на оптимизацию работы с файловой системой на уровне ядра PHP большинство людей повлиять не могут, поэтому она не оценивалась.
                                                  +1
                                                  а я и не говорю что нужно влиять. Нужно было при замерах использовать одну и ту же функцию для чтения файлов, думаю результат будет отличным от Вашего.
                                                    0
                                                    Например, вместо include($file) использовать eval('?'.'>'.file_get_contents($file).'<'.'?')
                                                    Или Вы имели в виду, что нужно избавиться от fopen/fgets/fclose и заменить на foreach (explode('\n', file_get_contents($file)) as $line)?
                                                    С последним, пожалуй, соглашусь, разница, наверное, будет.
                                                      0
                                                      последнее Вы верно поняли.
                                                        +1
                                                        Добавил пример с file_get_contents. Вопреки ожиданиям, разница не очень существенна, и, в основном, заметна для больших конфигов.
                                                        0
                                                        foreach (file($file) as $line)
                                                        
                                                          0
                                                          согласен с предыдущим оратором
                                                          и 5 копеек
                                                          $file_array = file($file);
                                                          foreach ($file_array as $line)
                                                  +5
                                                  Для полноты картины можно еще проверить JSON, YAML
                                                    +3
                                                    Хотя YAML должен быть достаточно медленным из-за отсутствия встроенных решений для парсинга, интереснее все же JSON.
                                                      0
                                                      Очень удобно хранить настройки в YAML, который спокойно и быстро читает и пишет свежая версия Zend Framework.
                                                        0
                                                        И благополучно конвертирует и кэширует их в pure php
                                                        • UFO just landed and posted this here
                                                        0
                                                        Как бы есть нативное решение ru2.php.net/manual/en/book.yaml.php
                                                        +1
                                                        Добавил JSON.
                                                        Методы парсинга данных средствами PHP, по идее, должны быть сравнимы с разбором текстовых файлов или даже медленнее.
                                                          0
                                                          Спасибо. Чтобы возвращало массив — можно второй параметр указать, но не думаю что на результаты это сильно повлияет
                                                            0
                                                            Спасибо, не учел.
                                                            В 99% случаев использую json_encode :-)
                                                        +5
                                                        Провел тесты приведённых скриптов на своей машине и о чудо… Настройки хранимые в php-скриптах на 20% быстрее, чем файлы с сериализованными массивами. Совершенно противоположные результаты.

                                                        Ошибка автора:
                                                        — Не учтено кэширование файлов ФС и кэширование данных PHP. Так как оба метода хранения данных (php-скрипты и сериализованные массивы в файлах) относительно мало различаются по скорости, то «играясь» с настройками кэширования можно добиться совершенно разных результатов.
                                                        На практике данный пример может действовать как и в положительную сторону, так и в отрицательную.
                                                          0
                                                          Согласен, не учел эти моменты.
                                                          А у Вас какие настройки кэширования данных PHP? Имеется ли какой-либо оптимизатор?
                                                            0
                                                            «стандартный» (с версии php 6.0 — internal)
                                                            php_APC
                                                            для «крутатинушки-крутатастой»:
                                                            apc.stat = «Off»
                                                            ну а потом в «нужные моменты времени»
                                                            apc_clear_cache('opcode');
                                                          0
                                                          XML надо было парсить через SimpleXML, результат был бы лучше. (проверено на собственной шкуре)
                                                          И еще, если на сервер поставить xcache — то чтение php файла с конфигом будет происходить мгновенно из рама (без учета дисковой операции). И по теории будет быстрее.
                                                            0
                                                            НапИшите примерчик? Буду благодарен!
                                                              0
                                                              function config($file)
                                                              {
                                                                  return simplexml_load_file($file);
                                                              }
                                                              
                                                                0
                                                                function config($file) {
                                                                    $xml = simplexml_load_file($file);
                                                                    $array = array();
                                                                    foreach($xml as $key => $value) {
                                                                        $array[$key] = (string)$value;
                                                                    }
                                                                    return $array;
                                                                }
                                                                


                                                                Как-то так…
                                                                А xcache — это расширение для php
                                                                    0
                                                                    Насколько помню к SimpleXML Object можно обращаться как к массиву, потому ваш цикл for — излишен. Если тип данных критичен, то можно просто рекурсивно скастовать тип через array_walk_recursive.
                                                                      0
                                                                      *SimpleXMLElement, старческая память
                                                                  +1
                                                                  В случае файла настроек, который будет преобразован в хеш-массив а DOM как таковой нафиг не нужен, нужно парсить потоковым SAX парсером.
                                                                    0
                                                                    Если стоит задача только читать конфиг из програмы (менять только ручками в редакторе), то быстрее будет делать через XMLReader. Особенно заметно на больших файлах.

                                                                    Правда конфиг прийдется привести к другому виду:

                                                                    1
                                                                    2
                                                                    3
                                                                      0
                                                                      Парсер рулит ))
                                                                      Вместо элетментов x1, x2, x3, ставить элемент param с аттрибутом name = x1, x2, x3.
                                                                    0
                                                                    Вообще-то если начинаешь задумываться о скорости, имеет смысл держать все в памяти – и настройки, и общие данные. Но в этом случае PHP, естественно, исключен.
                                                                      0
                                                                      Все эти танцы с бубном опять лишь для красоты, результаты предопределены. Вопрос в том, что делать дальше? Если это большой проект, где конфигурирование происходит из различных точек, никто не будет это переменными, ini файлами (многоуровневы конфигурации). Остается XML и JSON. Чаще всего применяется первый, не смотря на свою избыточность. Но никто не будет оставлять сборку и считыванию конфигов в голов виде. Будут кешировать на диск, в память, в memcache в результате ваша проделанная работа так и не раскрывает вопрос. Это сродни — функции работают быстрее классов, но мы ведь не будем все строить без ООП?
                                                                        0
                                                                        у нас ini + key-value кеш (redis, memcache)
                                                                          0
                                                                          Тестирование не совсем верное: нет гарантий что все использованные алгоритмы имеют линейную скорость работы и вдруг не завтормозят на десятке значений.
                                                                          Правильно бы было сгенерировать конфиг файл длиной хотя бы несколько десятков строк: это будет ближе к реальной ситуации.
                                                                            0
                                                                            Вы разве не об этом говорите?
                                                                            Конфигурационный файл содержит 10, 100 или 1000 конфигурационных параметров, представляющих собой короткие строки
                                                                              0
                                                                              Ай, зевнул. Именно этим и занимаются люди по утрам, верно? :))
                                                                            0
                                                                            Вот оно как всё… Никогда раньше особо не задумывался над конфигами.
                                                                              0
                                                                              Простите мою глупость, но терзает вопрос, – Что за магические три числа в ваших результатах? Я не придираюсь, а правда не понял…
                                                                              • UFO just landed and posted this here
                                                                                  0
                                                                                  Конфигурационный файл содержит 10, 100 или 1000 конфигурационных параметров, представляющих собой короткие строки. Соответственно 3 результата для каждого набора
                                                                                  +7
                                                                                  Это называется экономия на спичках. (Говоря русским языком, всё это онанизм для мозгов, и не более.)

                                                                                  Как я обычно говорю «если программисту кажется что тормозит язык программирования, значит тормозит сам программист.»
                                                                                    0
                                                                                    В чем-то Вы правы.
                                                                                    Чтение конфигов, по сути, редко является узким местом. Есть и более «узкие» места в скриптах.
                                                                                  • UFO just landed and posted this here
                                                                                      0
                                                                                      Спасибо!
                                                                                      Расскажите, пожалуйста, как Вы делаете диаграммы?
                                                                                      Я 90% времени в консоли, и, к стыду своему, не знаю, как это делается :-)
                                                                                      • UFO just landed and posted this here
                                                                                        • UFO just landed and posted this here
                                                                                            –1
                                                                                            На Pure CSS3, надеюсь?

                                                                                            :-)
                                                                                            • UFO just landed and posted this here
                                                                                            +1
                                                                                            В консоли тоже делается, gnuplot'ом :)
                                                                                            +1
                                                                                            Жесть. Не?

                                                                                            Вот как бы реально действующий код…

                                                                                            $Config = Helly_Config::GetInstance(); //Синглтон отнаследованный от ObjectArray

                                                                                            $Config['ТО'] = 1;
                                                                                            $Config['СЁ'] = 2'
                                                                                            $Config['ПЯТОЕ'] = 5;
                                                                                            //…
                                                                                            $Config['СТОПЯТОЕ'] = 105;
                                                                                            $Config['ОЛОЛОТРОЛОЛО'] = $Config['ПЯТОЕ'] == 5 ? 'это пять' : 'ничего подобного';


                                                                                            + Автозагрузчик классов движка.

                                                                                            Ну и в результате можно везде делать Helly_Config::Get('ТО'); Helly_Config::Get('СЁ'); Helly_Config::Get('ПЯТОЕ'); Helly_Config::Get('ДЕСЯТОЕ');

                                                                                            Счастлив и не парюсь пока. Вчера сайт (сидящий по соседству с ещё десятком сайтов) пережил две с половиной тысячи уникальных посетителей без каких-либо тормозов. Процессор Atom и оперативной памяти 2Gb (То есть обычный жиденький «сервер»). Акселератора нет.

                                                                                            ИТОГО:
                                                                                            Со Smarty, DbSimple (работает с мускулом) и кучей классов движка (каюсь, подгружаются лениво) без какого-либо кеширования страница генерируется в среднем за 0,1 сек.

                                                                                            Или я чего-то не понял… Честно, извините.
                                                                                              0
                                                                                              Ну и да. Попробуйте такое $Config['ОЛОЛОТРОЛОЛО'] = $Config['ПЯТОЕ'] == 5? 'это пять': 'ничего подобного'; в INI-файле сделать.

                                                                                              В ЖЖ наверное так за конфиги не гонят…
                                                                                                +2
                                                                                                > Вчера сайт (сидящий по соседству с ещё десятком сайтов) пережил две с половиной тысячи уникальных посетителей без каких-либо тормозов. Процессор Atom и оперативной памяти 2Gb (То есть обычный жиденький «сервер»). Акселератора нет.

                                                                                                Это не показатель крутости у меня на атоме, 1гб, около 60-80 тыс уников и 500 тыс просмотров
                                                                                                И проблема не в Атоме, а в том что канал всего 10мбит =)

                                                                                                Данные примеры будут полезны, только при очень большом наплыве пользователей
                                                                                                  0
                                                                                                  Жуть! Многим до такого ого-го…
                                                                                                  *Одел шляпу*
                                                                                                  – Снимаю шляпу.
                                                                                                  *Снял шляпу*

                                                                                                  > Данные примеры будут полезны, только при очень большом наплыве пользователей

                                                                                                  Ну почему у него в лучшем случае конфиг читается всего в два раза быстрее, чем у меня весь сайт работает (с известными шаблонизатором и БД)?!
                                                                                                    0
                                                                                                    А Вы какой конфиг имеете в виду — из 10 строк, 100 или 1000?
                                                                                                      –1
                                                                                                      Вот такой:
                                                                                                      <?php

                                                                                                      $Config = Helly_Config::GetInstance();

                                                                                                      // Site pathes:
                                                                                                      $Config['ROOT_DIR'] = ROOT_DIR;
                                                                                                      $Config['WEB_DIR'] = 'http://lastproof.ru';
                                                                                                      $Config['COOKIE_PATH'] = '.lastproof.ru';

                                                                                                      $Config['DIRS_RIGHTS'] = 0755;
                                                                                                      $Config['FILES_RIGHTS'] = 0644;

                                                                                                      // Metadata:
                                                                                                      $Config['META_TITLE'] = 'Последнее доказательство';
                                                                                                      $Config['META_DESCRIPTION'] = 'LastProof.Ru – генератор доказательств, непредвзято доказывающий что угодно.';
                                                                                                      $Config['META_KEYWORDS'] = 'доказательство, proof, спор, холивар, генератор доказательств, правосудие, пари, аргумент, доказательства, lastproof.ru';

                                                                                                      // Behaviour:
                                                                                                      $Config['SITE_DEFAULT_LANG'] = 'ru';
                                                                                                      $Config['SITE_PRODUCTION_MODE'] = false;
                                                                                                      $Config['SITE_SKIN'] = 'default';
                                                                                                      $Config['SITE_CLOSED'] = false;
                                                                                                      $Config['INVITES_ENABLED'] = false;

                                                                                                      // Basic directory:
                                                                                                      $Config['HELLY_DIR'] = HELLY_DIR;

                                                                                                      $Config['APPLICATION_DIR'] = APPLICATION_DIR;
                                                                                                      $Config['APPLICATION_WEB_DIR'] = $Config['WEB_DIR']. '/app';

                                                                                                      $Config['DATA_DIR'] = $Config['APPLICATION_DIR']. '/data';
                                                                                                      $Config['LANGUAGES_DIR'] = $Config['DATA_DIR']. '/langs';
                                                                                                      $Config['MODELS_DIR'] = $Config['APPLICATION_DIR']. '/models';
                                                                                                      //$Config['PLUGINS_DIR'] = $Config['APPLICATION_DIR']. '/plugins';

                                                                                                      $Config['SKINS_DIR'] = $Config['APPLICATION_DIR']. '/skins';
                                                                                                      $Config['SKINS_WEB_DIR'] = $Config['APPLICATION_WEB_DIR']. '/skins';
                                                                                                      $Config['SKIN_DIR'] = $Config['SKINS_DIR']. '/'. $Config['SITE_SKIN'];
                                                                                                      $Config['SKIN_WEB_DIR'] = $Config['SKINS_WEB_DIR']. '/'. $Config['SITE_SKIN'];

                                                                                                      $Config['PUBLIC_DIR'] = $Config['ROOT_DIR']. '/public';
                                                                                                      $Config['PUBLIC_WEB_DIR'] = $Config['WEB_DIR']. '/public';

                                                                                                      // Config for Helly_Router:
                                                                                                      $Config['HELLY_ROUTER'] = array (
                                                                                                      'allowed_controllers' => array (
                                                                                                      'home' => 'Controller_Home',
                                                                                                      'errors' => 'Controller_Errors',
                                                                                                      'gates' => 'Controller_Gates',
                                                                                                      'pages' => 'Controller_Pages',
                                                                                                      'proof' => 'Controller_Proof',
                                                                                                      ),
                                                                                                      'default_controller'=> 'home',
                                                                                                      'errors_controller' => 'errors',
                                                                                                      );

                                                                                                      // Config for Helly_Viewer:
                                                                                                      $Config['HELLY_VIEWER'] = array
                                                                                                      (
                                                                                                      'compile_check' => (false === $Config['SITE_PRODUCTION_MODE']? true: false),
                                                                                                      'caching' => false,
                                                                                                      'samples' => array(
                                                                                                      'content' => array('messages'),
                                                                                                      'sidebar' => array('empty'),
                                                                                                      ),
                                                                                                      );

                                                                                                      // Config for Helly_Database:
                                                                                                      $Config['HELLY_DATABASE'] = array (
                                                                                                      'db_configs' => array (
                                                                                                      'default' => array (
                                                                                                      'type' => 'mysql',
                                                                                                      'host' => '***.**.***.***',
                                                                                                      'port' => '****',
                                                                                                      'user' => '**********',
                                                                                                      'pass' => '**********',
                                                                                                      'db_name' => '**********',
                                                                                                      'prefix' => '****',
                                                                                                      'charset' => 'utf8'
                                                                                                      ),
                                                                                                      'xbt' => array (
                                                                                                      'type' => 'mysql',
                                                                                                      'host' => '***.**.***.***',
                                                                                                      'port' => '****',
                                                                                                      'user' => '*******',
                                                                                                      'pass' => '********',
                                                                                                      'db_name' => '*******',
                                                                                                      'prefix' => '****',
                                                                                                      'charset' => 'cp1251'
                                                                                                      ),
                                                                                                      ),
                                                                                                      'log_errors' => true, // Log sql errors.
                                                                                                      'log_queries' => true, // Log all sql queries.
                                                                                                      );

                                                                                                      // Config for Helly_Cacher:
                                                                                                      $Config['HELLY_CACHER'] = array (
                                                                                                      'cache_enabled' => true, // bool
                                                                                                      'cache_type' => 'memory', // string[files/memory]

                                                                                                      'cache_prefix' => Helly_UriManager::ClearUri($Config['WEB_DIR']), // Prefix for files of cache
                                                                                                      'cache_dir' => $Config['DATA_DIR']. '/cache', // Directory for files of cache

                                                                                                      'memcached_servers' => array( // Settings for connecting to memcached servers
                                                                                                      array(
                                                                                                      'host' => '*************',
                                                                                                      'port' => *****,
                                                                                                      'persistent'=> true
                                                                                                      ),
                                                                                                      ),
                                                                                                      'memcached_compression' => true, // Use memcached compression
                                                                                                      );

                                                                                                      // Sending E-mails:
                                                                                                      $Config['HELLY_MAILER'] = array (
                                                                                                      'type' => 'smtp', // string[php/smtp]
                                                                                                      'email' => '*******************',
                                                                                                      'from' => $Config['META_TITLE'],
                                                                                                      'smtp_host' => 'smtp.yandex.ru',
                                                                                                      'smtp_port' => 25,
                                                                                                      'smtp_user' => '*******************',
                                                                                                      'smtp_password' => '********',
                                                                                                      'smtp_auth' => true,
                                                                                                      );

                                                                                                      // Logging:
                                                                                                      $Config['LOGS_DIR'] = $Config['DATA_DIR']. '/logs';
                                                                                                      $Config['LOGS_FILE'] = 'helly.log';

                                                                                                      ?>

                                                                                                      ↑ это в оригинале 143 строки

                                                                                                      И там ниже – што-што, простите? Не понял – вы для генерации одной страницы «считываете конфиг» более одного раза?
                                                                                                        +2
                                                                                                        Ну есть же сервисы для обмена исходными текстами.
                                                                                                          0
                                                                                                          Ну есть же нормальные, менее депресовые роботы.
                                                                                                      0
                                                                                                      Возможно он использует FCGI… если вы свой сайт переведете на FCGI у вас тоже вырастит скорость…
                                                                                                      Вот к примеру: ava.md/ — если без FCGI, тогда будет около 0.1-0.2сек, с FCGI 0.02 — и то 0.01 — тратится на PREG который ужимает HTML
                                                                                                        0
                                                                                                        время генерации можно посмотреть, правой клавишей, вторая строчка =)
                                                                                                          0
                                                                                                          У него растёт не скорость, а время выполнения. То есть всё очень МЕДЛЕННО. Или я чего-нибудь про единицы измерения не понял. Их разрядность…
                                                                                                          0
                                                                                                          > Ну почему у него в лучшем случае конфиг читается всего в два раза быстрее, чем у меня весь сайт работает (с известными шаблонизатором и БД)?!

                                                                                                          Время считается для цикла из 1000 загрузок конфига. А у Вас генерируется 1 страница
                                                                                                      • UFO just landed and posted this here
                                                                                                        • UFO just landed and posted this here
                                                                                                        0
                                                                                                        Может быть автор диаграммы в топик перенесет?
                                                                                                        +2
                                                                                                        Смею не согласится с автором.

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

                                                                                                        Никто никогда не сомневался, парсинг XML в DOM это дорогая операция, но за удобство всегда нужно платить.

                                                                                                        Откровенно говоря, все зависит от общей схемы работы и структуры.

                                                                                                        Для меня удобнее хранить в XML (в атрибутах узлов я могу хранить что угодно и парсить данные на основе этого).
                                                                                                          0
                                                                                                          > астройки читаются один раз и доступны на протяжении работы сценария
                                                                                                          А это как написать :)
                                                                                                            0
                                                                                                            Вы же не читаете файл конфига каждый раз при обращении за неким свойством, а первый раз читаете в массив к примеру.
                                                                                                              0
                                                                                                              Ну я, положим, не читаю =)
                                                                                                                0
                                                                                                                Приходилось переписывать код, читающий настройки по одной из БД каждый раз, когда они становились нужны. Переписывал, и мысленно отрывал руки кодеру.
                                                                                                            • UFO just landed and posted this here
                                                                                                                0
                                                                                                                Где можно сделать запрос на Хабраэффект? :)
                                                                                                                  +5
                                                                                                                  [a href=«yousite.com/»]сиськи здесь [/a] (В BB тегах потому что так надо :)
                                                                                                                    +3
                                                                                                                    Зачем Вы положили yousite.com??? Они теперь страдают!
                                                                                                                    • UFO just landed and posted this here
                                                                                                                      0
                                                                                                                      [img]http://yousite.com/[/img] Так даже про сиськи писать не нужно
                                                                                                                    0
                                                                                                                    Я сказал, что для оптимизации (обычно) есть более подходящие процессы.
                                                                                                                  0
                                                                                                                  интересно было бы узнать какими либами и их версиями проводилось считывание, а также резличие в одних и тех же форматах для различных поставленных вами «условий»… а то картинка не чёткая…
                                                                                                                    –8
                                                                                                                    модераторы удалите топик, не позорьте ресурс
                                                                                                                      +22
                                                                                                                      Ага, не понятно что делает технический топик на новостном и развлекательном ресурсе.
                                                                                                                        +2
                                                                                                                        Может ваш оппонент так смеётся над полученными данными?
                                                                                                                      0
                                                                                                                      А я вообще ничего не понял, у меня и так все нормально работает.
                                                                                                                        +2
                                                                                                                        чтобы JSON возвращал не stdClass object, а массив надо в функции json_decode 2 параметром дописать true
                                                                                                                          –4
                                                                                                                          Опять экономят крохи не обращая внимания на слонов.
                                                                                                                          ini файлы — наиболее удобны в использовании, ими и надо пользоваться.
                                                                                                                            +1
                                                                                                                            Когда как. Заглядите внутрь Мадженты и прикиньте как бы вы это делали ини-шками :)
                                                                                                                              0
                                                                                                                              В Мадженте масса «слонов» :)
                                                                                                                            +1
                                                                                                                            Кстати при увеличении массива данных, json_decode себя покажет куда лучше чем unserialize.
                                                                                                                              0
                                                                                                                              У Вас есть весомые аргументы для этого?
                                                                                                                                0
                                                                                                                                Массив заполняется $size (amount of enrites в результатах) случайными строковыми значениями:
                                                                                                                                8-16 символов ord(rand(32, 128));
                                                                                                                                Затем сериализуется.
                                                                                                                                Время выполнения предлагается:
                                                                                                                                $seconds = sqrt($size / 10000);


                                                                                                                                Дальше идёт адаптивная схема измерения времени выполнения
                                                                                                                                $time1 = microtime(true);
                                                                                                                                $time2 = $time1;
                                                                                                                                $calls = 0;
                                                                                                                                while ($time2 <= $time1 + $seconds) {
                                                                                                                                	unserialize($string);
                                                                                                                                	$time2 = microtime(true);
                                                                                                                                	$calls++;
                                                                                                                                }
                                                                                                                                

                                                                                                                                время выполнения одного вызова (в мс):
                                                                                                                                ($time2 - $time1)*1000 / $calls


                                                                                                                                Аналогично для json
                                                                                                                                data size — размер сериализованных данных.

                                                                                                                                amount of enrites: 10000
                                                                                                                                data size: 387860
                                                                                                                                    calls: 182
                                                                                                                                serialize: 5.4978132247925 ms
                                                                                                                                data size: 268961
                                                                                                                                    calls: 90
                                                                                                                                     json: 11.220910814073 ms
                                                                                                                                
                                                                                                                                amount of enrites: 50000
                                                                                                                                data size: 1983594
                                                                                                                                    calls: 73
                                                                                                                                serialize: 30.974479121049 ms
                                                                                                                                data size: 1344695
                                                                                                                                    calls: 39
                                                                                                                                     json: 57.372336890754 ms
                                                                                                                                
                                                                                                                                amount of enrites: 240000
                                                                                                                                data size: 9703391
                                                                                                                                    calls: 18
                                                                                                                                serialize: 276.30117538543 ms
                                                                                                                                data size: 6454491
                                                                                                                                    calls: 18
                                                                                                                                     json: 279.90789217722 ms


                                                                                                                                Другое дело, что в контексте статьи это утверждение бессмысленно, ибо конфиги (мы же их рассматривали?) на 250 тысяч записей — это какой-то кошмар. И скрипту при таких размерах данных 64МБ уже не хватает.
                                                                                                                                  0
                                                                                                                                  И ведь не поспоришь :-)
                                                                                                                                  Да, такие большие конфиги я не рассматривал
                                                                                                                            • UFO just landed and posted this here
                                                                                                                              • UFO just landed and posted this here
                                                                                                                                  0
                                                                                                                                  Спасибо!
                                                                                                                                  0
                                                                                                                                  Насчет file():
                                                                                                                                  Попробовал, на маленьких файлах получается чуточку быстрее, на больших — медленнее.
                                                                                                                                  Спасибо, как освобожусь — включу в статью дополнение
                                                                                                                                  • UFO just landed and posted this here
                                                                                                                                      0
                                                                                                                                      Собственно, топик возник в результате размышлений над большими конфигами :-)
                                                                                                                                        –1
                                                                                                                                        Конфиг (на мой взгляд) — это просто набор обязательных параметров для старта приложения. А вы оперируете этим словом как неким метасимволом «все, что настраиваемо».
                                                                                                                                        Например, конфиги бывают разные у разных пользователей (темы оформления, как один пример из тысячи).

                                                                                                                                        Я вижу понятие «конфиг» как некий «ключ для входа в пространство приложения». Такой конфиг никогда не разростется даже до масштаба 100 строк, поэтому его можно читать хоть побуквенно.

                                                                                                                                        Далее — уже встает второй вопрос. Есть туча настроек конкретно этой сессии. Что делать с ними? ini/php-файлы на этом этапе выглядят уже странно. Я стараюсь вытащить на старте сессии все из базы, и закешировать (да, для анонимных сессий — в памяти, для авторизаций — в зависимости от посещаемости ресурса).
                                                                                                                                        • UFO just landed and posted this here
                                                                                                                                            +1
                                                                                                                                            Эт вам на JavaEE надо пописать: полдня конфигуришь — полчаса пишешь =)

                                                                                                                                            ЗЫ утрирую, конечно, но конфиги там по полной используются.
                                                                                                                                              0
                                                                                                                                              «Ключ для входа в пространство приложения» может занимать куда больше 100 строк даже без комментариев и пустых строк. Особенно в случае динамического связывания компонентов приложения, когда вам нужно чуть ли не для каждого поля класса (хорошо, если не объекта) указывать с какими другими классами и как он связан.
                                                                                                                                      0
                                                                                                                                      В парсинге текстового файла можно ещё чуть-чуть ускорить работу заменив:
                                                                                                                                      foreach (explode("\n", file_get_contents($file)) as $line) {
                                                                                                                                      на
                                                                                                                                      foreach (file($file) as $line) {

                                                                                                                                        0
                                                                                                                                        Попробовал, на маленьких файлах получается чуточку быстрее, на больших — медленнее.
                                                                                                                                        Спасибо, как освобожусь — включу в статью дополнение
                                                                                                                                        • UFO just landed and posted this here
                                                                                                                                            0
                                                                                                                                            С последним пунктом однозначно соглашусь — код должен генерировать по минимуму warning'ов и даже notice'ов. Но задача была оптимизировать работу скриптов по максимуму, избежать лишних проверок, и т.п. Чтобы не было «тормозов» из-за этих проверок. Поэтому код получился именно «тестовый», а не рабочий.
                                                                                                                                          –2
                                                                                                                                          исследование ни о чём, кофиги нужно хранить в удобном виде, а затем кэшировать в шареную память: smop, apc, memcache…
                                                                                                                                          подход ни о чём. куча слов о железе, но сейчас нет ничего о том, как делались замеры. тестировать лучше сторонними утилитами и парокой левых инклудов, чтобы исключить влияние файлового кэша ОС. например, ab с конкурентными запросами, как в реальной жизни.
                                                                                                                                            0
                                                                                                                                            > исследование ни о чём

                                                                                                                                            Позвольте с Вами не согласиться

                                                                                                                                            > кофиги нужно хранить в удобном виде, а затем кэшировать в шареную память: smop, apc, memcache…

                                                                                                                                            Вообще-то да. Но сколько % людей, которые программируют на PHP, так делают?

                                                                                                                                            > подход ни о чём. куча слов о железе

                                                                                                                                            Ровно 1 предложение о железе было добавлено после того, как получено достаточно комментариев открыто и в личку

                                                                                                                                            > но сейчас нет ничего о том, как делались замеры

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

                                                                                                                                            > тестировать лучше сторонними утилитами и парокой левых инклудов

                                                                                                                                            Почему сторонними? Тогда ведь нужно считать время старта PHP-интерпретатора. Я тестировал из командной строки, время считалось вызовами microtime() до и после 1000 итераций загрузки конфигов

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

                                                                                                                                            А почему его нужно исключать?.. В реальной жизни же все используют кэш ОС. И если какой-то из алгоритмов использует его более эффективно — то ура, товарищи!
                                                                                                                                              0
                                                                                                                                              >Вообще-то да. Но сколько % людей, которые программируют на PHP, так делают?
                                                                                                                                              А скольки процентам людей реально нужны эти миллисекунды чтения конфигов? ;-)
                                                                                                                                              Когда я писал менеджер конфигов в средне-нагруженном проекте, то использовал SQL+memcache.
                                                                                                                                                0
                                                                                                                                                Да вряд ли кому.
                                                                                                                                                Я вот чисто для интереса поисследовал :-)
                                                                                                                                                –1
                                                                                                                                                >>Вообще-то да. Но сколько % людей, которые программируют на PHP, так делают?

                                                                                                                                                те, кому нужно считать миллисекунды так делают.

                                                                                                                                                >>Я тестировал из командной строки, время считалось вызовами microtime() до и после 1000 итераций загрузки конфигов

                                                                                                                                                вот об этом я и писал, что ничего не было о том, как делаются замеры. а они делаются так как и предполагалось — цикл из ПОСЛЕДОВАТЕЛЬНЫХ запросов к ОДНОМУ файлу. эпик фэйл, не имеющий никакого отношений к реальной жизни.

                                                                                                                                                я бы прошёл мимо, если бы не пришлось последних два месяца разгребать проект, сделаный такими горе-оптимизаторами. вы здесь понаписовали и многие принимают это за чистую монету и будут завтра с пеной у рта доказывать, они же на хабре прочитали. тьфу.
                                                                                                                                              0
                                                                                                                                              графиков нехватает… было бы намного удобнее подрезюмировать
                                                                                                                                              +1
                                                                                                                                              Вообще, ИМХО исследование бесполезно по определению. Все равно, где хранить данный. Нужно выбирать тот формат, который удобней. Если вы рулите реально большой системой, на которой будет заметны такие мелочи, то вы будете кешировать конфиг.
                                                                                                                                                +1
                                                                                                                                                Просто кешируем прочитанные с конфига значения и нам все равно сколько они парястя первый раз, главное что бы было удобно менять их.
                                                                                                                                                  0
                                                                                                                                                  Ага, и я так тоже решил :-)
                                                                                                                                                    –1
                                                                                                                                                    С другой стороны можно сделать интерфейс к изменению конфига и тогда все равно в каком формате их хранить с точки зрения удобства изменения :)
                                                                                                                                                    0
                                                                                                                                                    Выложите архив со скриптами для тестирования, чтобы каждый мог запустить на своей системе и проверить, что будет быстрей.
                                                                                                                                                    0
                                                                                                                                                    Провел небольшой тест:

                                                                                                                                                    Код:
                                                                                                                                                    $time = new DateTime();
                                                                                                                                                    echo "Start:".$time->getTimestamp().PHP_EOL;
                                                                                                                                                    
                                                                                                                                                    $mc= new Memcache;
                                                                                                                                                    $mc->connect('localhost', 11211);
                                                                                                                                                    
                                                                                                                                                    $key = "_config1000";
                                                                                                                                                    
                                                                                                                                                    for ($i=0; $i<10000; $i++) {
                                                                                                                                                      $config = $mc->get($key);
                                                                                                                                                    
                                                                                                                                                      if (!$config) {
                                                                                                                                                        $config = parse_ini_file('test.ini');
                                                                                                                                                        $mc->add($key, serialize($config));
                                                                                                                                                      }
                                                                                                                                                    }
                                                                                                                                                    
                                                                                                                                                    
                                                                                                                                                    $time = new DateTime();
                                                                                                                                                    echo "End:".$time->getTimestamp().PHP_EOL;
                                                                                                                                                    


                                                                                                                                                    ini-файл, 1000 параметров, 10000 итераций, без использования кеша:

                                                                                                                                                    Start:1295868628
                                                                                                                                                    End:1295868639

                                                                                                                                                    (11 секунд)

                                                                                                                                                    этот же файл с использованием memcache:
                                                                                                                                                    Start:1295868721
                                                                                                                                                    End:1295868723

                                                                                                                                                    (2 секунды)

                                                                                                                                                    Очевидно что лучше его таки использовать:)
                                                                                                                                                      +2
                                                                                                                                                      $mc->add($key, serialize($config));

                                                                                                                                                      serialize() то зачем? драйвер мемкеша его автоматически делает. И Unserialize вы не делаете.

                                                                                                                                                      И время соединения с мемкешем только один раз посчитали, хотя нужно на каждой итерации делать connect()
                                                                                                                                                        –1
                                                                                                                                                        Да, я не заморачивался, ну суть в принципе та же
                                                                                                                                                          +1
                                                                                                                                                          Но вывод, скорее всего, будет другой. Особенно если время connect() посчитать для каждой итерации.

                                                                                                                                                          Хотя, если мемкеш используется в самом проекте и коннект нужно делать в любом случае, то да, можно время коннекта отбросить
                                                                                                                                                          0
                                                                                                                                                          Прогнал с исправлениями, получилось:
                                                                                                                                                          Start:1295874910
                                                                                                                                                          End:1295874923

                                                                                                                                                          Start:1295874893
                                                                                                                                                          End:1295874896

                                                                                                                                                          Redis тоже, кстати, показал 3 секунды:
                                                                                                                                                          $time = new DateTime();
                                                                                                                                                          echo "Start:".$time->getTimestamp().PHP_EOL;
                                                                                                                                                          
                                                                                                                                                          require_once 'Rediska.php';
                                                                                                                                                          
                                                                                                                                                          for ($i=0; $i<100000; $i++) {
                                                                                                                                                            $options = array(
                                                                                                                                                              'namespace' => 'Auto3_',
                                                                                                                                                              'servers'   => array(
                                                                                                                                                                  array('host' => '127.0.0.1',
                                                                                                                                                                        'port' => '6379'
                                                                                                                                                                  )
                                                                                                                                                              )
                                                                                                                                                            );
                                                                                                                                                          
                                                                                                                                                            $rediska = new Rediska($options);
                                                                                                                                                          
                                                                                                                                                            $keyn = "__conf1000";
                                                                                                                                                            $key = new Rediska_Key($keyn);
                                                                                                                                                            $config = $key->getValue($keyn);
                                                                                                                                                          
                                                                                                                                                            if (!$config) {
                                                                                                                                                              $config = parse_ini_file('test.ini');
                                                                                                                                                              $key->setValue($config);
                                                                                                                                                            }
                                                                                                                                                          }
                                                                                                                                                          
                                                                                                                                                          $time = new DateTime();
                                                                                                                                                          echo "End:".$time->getTimestamp().PHP_EOL;
                                                                                                                                                          
                                                                                                                                                          
                                                                                                                                                            0
                                                                                                                                                            Только там 10 000 итераций, а не 100 000
                                                                                                                                                        0
                                                                                                                                                        Еще конфиги можно хранить в формате YML.

                                                                                                                                                        Довольно приятно читается.

                                                                                                                                                        Для парсинга мы применяем компоненту из фреймворка Symfony (http://components.symfony-project.org/yaml/).
                                                                                                                                                        Результат кешируем в виде php кода.

                                                                                                                                                        После сохранения результата в кеш быстродействие будет сравнимо с хранением конфигов в виде обычного PHP.

                                                                                                                                                        • UFO just landed and posted this here
                                                                                                                                                          +1
                                                                                                                                                          Я на пхп конечно давно уже не пишу. Но какой процент от общего времени выполнения занимает инициализация конфига?
                                                                                                                                                          • UFO just landed and posted this here
                                                                                                                                                              0
                                                                                                                                                              А можно точнее? в процентах, мне действительно интересно что побудило автора провести такое исследование.
                                                                                                                                                              • UFO just landed and posted this here
                                                                                                                                                                  0
                                                                                                                                                                  Предыстория простая.

                                                                                                                                                                  Когда одним скриптом (ну, точнее, одним вызовом) генерируется большая HTML-страница — то % времени на чтение конфигов маленький. Ну, например, 1/1000 времени работы скрипта.

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

                                                                                                                                                                  Когда скриптом генерируются AJAX-ответы — то, бывает, еще больше.

                                                                                                                                                                  Например, я недавно видел подобный скрипт, который позволял реализовать часы в браузере: время на часах через AJAX-запросы к серверу синхронизировалось с серверным. Так вот, чтобы отдать клиенту текущее время, скрипт предварительно лез в конфиги, чтобы посмотреть формат времени-даты. Это, конечно, можно считать мисдизайном, потому что формат можно было принимать от клиента. Но это как посмотреть.

                                                                                                                                                                  Так вот, это я к чему… Чтение конфигов в этом скрипте составляло что-то около 90% времени. А запросов к нему было достаточно много (больше, чем к страницам). А теперь представьте, что этот скрипт случайно был бы включен в phpBB, и конфиги бы хранились в базе данных…

                                                                                                                                                                  Отсюда и интерес к исследованию скорости: чем меньше скрипты и чем больше раз они вызываются, тем более оптимизированы они должны быть.
                                                                                                                                                                    0
                                                                                                                                                                    кхм, а почему бы время/дату не передавать в unix timestamp? конфиги вообще не нужны в таком случае :)
                                                                                                                                                            • UFO just landed and posted this here
                                                                                                                                                                0
                                                                                                                                                                пока не могу себе представить такой проект, в котором были бы сотни мегабайт настроек…
                                                                                                                                                                  0
                                                                                                                                                                  после длительного использования symfony привык держать конфиги в yml файлах. С кэшированием в php-массивы, разумеется. Читать и править такие конфиги удобно, на выходе очень гибкий и быстрый php-код, без необходимости что-либо парсить при каждом запуске скрипта.
                                                                                                                                                                    0
                                                                                                                                                                    спасибо за полезную статью. Возьму на вооружение. Был удивлён высоким результатом ini-файлов.
                                                                                                                                                                      0
                                                                                                                                                                      Не пробовали хранить настройки в SQLIte? Интересно было бы добавить к тестам и такой вариант. Конечно он проиграет в сравнении с тем же INI или нативным PHP, но, иногда нужно дать возможность менять настройки через CMS, и вот тут выбор как лучше организовать хранение и куда писать эти настройки.

                                                                                                                                                                      Only users with full accounts can post comments. Log in, please.