Jakiś czas temu we wpisie ,,Prosty pająk sieciowy‘’ (link tutaj) przedstawiłem połączenie skryptu w Perlu i skryptu w R, które wykorzystywałem do zbierania danych o samochodach z serwisu otomoto.pl.
W komentarzach do wpisu użytkownik Maciej opisał podobne rozwiązanie, ale zamiast skryptu w Perlu wykorzystujące pakiet XML (dostępny dla programu R w repozytorium CRAN). Rozwiązanie Maćka ma kilka zalet nad hybryda R+Perl, z mojego punktu widzenia, największa zaleta jest taka, że ,,wszystko’’ dzieje się w R. Łatwiej utrzymać, przenosić i rozwijać rozwiązanie, które jest bardziej jednolite.
Spodziewany koszt tej jednolitości to czasu działania. Wydawało (mi) się, że Perl jako narzędzie do przetwarzania tekstów i działania na stronach internetowych powinien być szybszy od R. Pytanie jaka będzie różnica w czasach działania?
Maciej Beręsewicz przygotował dwa skrypty w R, które wykonują praktycznie te same operacje co mój skrypt w Perlu. Pierwszy skrypt (wersjaStrsplitMB.R) wykorzystuje funkcję getURL() aby ściągnąć źródła strony a następnie używa funkcji strsplit() by wydobyć ze źródła HTML interesujące rzeczy. Drugi skrypt (wersjaXMLMB.R) wykorzystuje funkcję htmlParse() od odczytania i parsowania dokumentu HTML, a następnie xpathApply() do operacji na przetworzonym wstępnie dokumencie. Oba skrypty są dostępne w tym katalogu.
Aby porównać czasy działania uruchomiłem te trzy wersje (Perl, R z strsplit i R z XML) kilkukrotnie. Za każdym razem ściągając informacje o 4 tyś aut. Testy rożnych rozwiązań odbyły się na tej samej maszynie, na szerokopasmowym łączu (wykorzystywany tylko jeden węzeł o wydajności odpowiadającej intel i7). Testy wykonałem o różnych godzinach by zobaczyć jak wpływ na czasy będzie miało natężenie ruchu w sieci, ale koniec końców otrzymałem bardzo powtarzalne wyniki, bez względu na godzinę czy dzień wykonania testów. Więc niżej pokażę tylko medianowe wyniki z różnych uruchomień.
Porównywane wersje:
- Wersja P = Perl + wczytanie danych do R
- Wersja R1 = R ściąganie getURL() i parsowanie z użyciem funkcji strsplit()
- Wersja R2 = R ściąganie i parsowanie z użyciem funkcji htmlParse()
Medianowe czasy działań i odpowiadająca im wydajność liczna w liczbie ,,przetworzonych’ 'stron opisujących kolejne auta na sekundę
Wersja testowana Wydajność Czas pobierania
liczona aut/sec i przetwarzania 4tys aut
Wersja P 4.61 aut/sec 867 sekund ( < 15 min)
Wersja R1 2.93 aut/sec 1365 sekund ( < 23 min)
Wersja R2 4.19 aut/sec 954 sekund ( < 16 min)
Ponieważ profilowanie kodu w R jest cudownie proste sprawdziłem też, które elementy ,,zżerają’’ najwięcej czasu w obu wersja Rowych. Poniżej wyniki dla medianowego czasu działania (tylko operacje najbardziej czasochłonne)
Wersja R1
total.time total.pct
getURL 714.08 52.53
strsplit 633.30 46.58
Wersja R2
total.time total.pct
htmlParse 919.01 96.21
W wersji R1, ponad 99% czasu zużyte jest te dwie operacje. Dodatkowy narzut związany z pętlami, zapisywaniem na dysku itp to mniej niż 1%. Z tych dwóch operacji mniej więcej tyle samo czasu trwa odczytywanie HTML przez sieć co jego parsowanie.
W wersji R2 większość czasu przetwarzania to wywołanie htmlParse(), która jest opakowaniem odwołania do funkcji napisanej w C.
Pointa?
Wersja perlowa jest najszybsza, ale wersja używająca pakietu XML jest niewiele wolniejsza. Biorąc pod uwagę dodatkowo długość kodu, jednolitość bardziej podoba mi się rozwiązanie Macka używające pakietu XML.