Test był prosty. Należało wczytać do pamięci listę pięćdziesięciu opcji konfiguracyjnych podzielonych na pięć grup. Dodatkowo w pliku znajdowało się dziesięć identycznych komentarzy. Każdy ze skryptów musiał załadować to wszystko do zmiennej $info i tyle - wyświetlenie już nie było potrzebne. Konfiguracja w każdym przypadku była przechowywana w osobnym pliku (tak więc nawet "skrypt PHP" musiał wykonać operację require), a wszystko po to, że normalnie właśnie z czymś takim mamy do czynienia i aplikacja jakieś operacje dyskowe musi wykonać. Skrypty są tak proste, że każdy może podobną procedurę na bazie opisu samodzielnie zrealizować w kwadrans i nie ma sensu ich tutaj publikować. Opiszę teraz każdy z testowanych formatów oraz to, czego się po nim spodziewałem:
- Zserializowane tablice - jest to zwykła reprezentacja tablicy lub obiektu PHP za pomocą ciągu tekstowego, dzięki czemu można ją przesyłać np. w ciastkach. Format jest zoptymalizowany do przetwarzania maszynowego, dlatego ręczna edycja takich danych to masochizm. Najbardziej jest przydatny, gdy skrypt musi scache'ować jakieś dane w celu użycia przez późniejsze żądania HTTP. Szybkość przetwarzania zserializowanych tablic mierzyłem już wcześniej i wiem, że pod tym względem nie powinny mieć one konkurencji.
- Pliki INI - PHP posiada parser plików INI z identyczną składnią, jak php.ini. Wystarcza on w zupełności do reprezentowania zbioru par nazwa => wartość, opcjonalnie podzielonych na grupy oraz z komentarzami, ale bardziej skomplikowane relacje (np. takie, jakie spotykamy w Zend Frameworku), trzeba implementować samemu.
- XML - format bardzo rozbudowany i umożliwia reprezentację nawet bardzo złożonych zbiorów. Ponadto istnieje szereg dedykowanych narzędzi do edycji oraz przetwarzania XML. Możemy łatwo sprawdzić poprawność pliku lub sformatować go poprzez XSLT. Z drugiej strony, jego składnia jest przydługawa i najprostsze rzeczy ciągną się na wiele znaków kodu, zaś oferowana ilość możliwości jest często zbyt duża - gdy widzę, że ktoś używa go do zwyczajnego reprezentowania par nazwa => wartość bez jakiejś naprawdę wyższej przyczyny, to mnie coś trafia (np. wspomnianego formatowania, choć osobiście nie wiem, na co komu formatowanie konfiguracji każdego poranka :)).
- YAML - stosunkowo młody język opisu danych, którego zaletą jest duże zbliżenie do naturalnego dla typowego człowieka zapisu (tyle że ustandaryzowane) oraz możliwość przetwarzania nawet prostymi wyrażeniami regularnymi, jako że składnia jest łatwa do obróbki maszynowej. YAML wykorzystują niektóre z frameworków, także tych napisanych w PHP. Z drugiej strony nie ma tutaj DTD, XSLT i jeśli ktoś bez tego żyć nie może, to będzie narzekać. Ponadto, dla PHP wciąż nie istnieje żadne kompilowane rozszerzenie służące do przetwarzania YAML, tak więc jesteśmy skazani na skryptowe parsery, co budziło u mnie obawy, jeśli chodzi o wydajność. W testach wykorzystałem parser Spyc.
- Skrypty PHP - wiele aplikacji zapisuje swoje konfiguracje bezpośrednio jako pewien plik PHP, w którym inicjowanych jest nieco zmiennych. Zaleta to możliwość przetworzenia bezpośrednio przez parser PHP, lecz z drugiej strony biada temu, kto popełni jakiś błąd składni, albo dopisze do skryptu jakiś złośliwy kod. Ponadto tworzenie bardzo rozbudowanych struktur nie musi być wygodne - to zależy od przyjętych konwencji, ponieważ tu możemy dosłownie wszystko.
Do testowania wykorzystałem program Apache Bench z opcjami -n 500 -c 50 (wyślij 500 żądań HTTP, po 50 jednoczesnych). Oto wyniki po kilku próbach w kolejności od najlepszego:
- Zserializowane tablice - ok. 4160 req/s.
- Skrypty PHP - ok. 3780 req/s.
- Pliki INI - zazwyczaj ok. 3300 req/s, ale bywały też sięgające 3900 req/s.
- XML - ok. 2800 req/s.
- YAML - ok. 250 req/s.
Tak, jak przypuszczałem - skryptowy parser YAML-a zupełnie nie poradził sobie w konkurencji z parserem XML, lecz ten z kolei przegrał z prostszymi formatami. Zastanawiające może być, że pliki INI o całkiem prostej składni są przetwarzane wolniej, niż skrypty PHP. Wniosek jest jeden: twórcy nie przywiązywali dużej wagi do optymalizacji prostszego parsera, gdyż przede wszystkim służy on jedynie do załadowania pliku php.ini, a to jest robione raz na długi czas. Spróbowałem sprawdzić, czy jest dla YAML-a jakiś ratunek poprzez cache'owanie wyniku działania w zserializowanych tablicach. Przerobiony skrypt musiał sprawdzić, czy istnieje scache'owana wersja i jeśli nie, to ją wygenerować. Rezultat znacznie się poprawił, aczkolwiek nadal nie dogonił reszty - ok. 850 req/s.
Podsumowując: dla prostych danych pozostanę przy plikach INI oraz tablicach tworzonych bezpośrednio w skryptach. Bardziej złożoną zawartość pozostawię parserowi XML wspomożonemu przez zserializowane tablice. Niestety, dopóki nie pojawi się szeroko stosowane i kompilowane rozszerzenie do parsowania YAML, w aplikacjach kładących duży nacisk na wydajność nie widzę za bardzo miejsca, chyba że przy jakichś sporadycznie wykonywanych operacjach.
Dopisek: mała poprawka, rozszerzenie do YAML jest już w repozytorium PECL, ale w wersji mocno-beta. Przeoczyłem je z powodu idiotycznej wyszukiwarki pakietów, która na zapytanie "YAML" pokazała odpowiedź "No matches found". Postaram się je skompilować i dołączyć wyniki z testów do wpisu.















Napisał Anonymous w wtorek, 4 września 2007 o 16:50
Przechowuję konfigurację w plikach .PHP, lecz myślę, czy nie przenieść się na zserializowane tablice. Zaleta - nie potrzeba funkcji zapisującej poprawnie te dane. Jest jeden problem - jeśli na serwerze .htaccess nie działa, każdy sobie zobaczy zawartość pliku (dotyczy szczególnie darmowych kont). Którą metodę z tych 2 więc lepiej zastosować?