Regexp performancia (python vs ruby vs java) [Részben megoldva/lezárva]

Fórumok

Nem értem.
Megírtam (szerintem) ugyanazt a programocskát három különböző nyelven.
Arra számítottam, hogy leggyorsabb a java, utána a ruby, leglassúbb a python lesz.
Ehhez képest:

HZ@teszt:~$ time python l1.py
732241 837

real 0m1.780s
user 0m1.614s
sys 0m0.162s
HZ@teszt:~$ time ruby l1.rb
732241
837

real 0m3.752s
user 0m3.213s
sys 0m0.535s
HZ@teszt:~$ time java L1
732241,837

real 0m3.394s
user 0m3.191s
sys 0m0.410s
HZ@teszt:~$

python: http://pastebin.com/mNZ6x2NN
ruby: http://pastebin.com/YrC9YdSG
java: http://pastebin.com/mfGLap0W

Hogy lehet, hogy még a java is ennyivel lassúbb a pythonnál?
(lehet valahogy optimalizálni a java-n - openjdk7 egyébként - vagy a python tényleg ennyivel gyorsabb nála?)

update: közben megcsináltam perlben is.
$ time perl l1.pl
732241 837

real 0m1.252s
user 0m1.118s
sys 0m0.134s

Ha sokszor futtatom őket felváltva, akkor is úgy 5-10%-kal gyorsabb a pythonnál. Ebből az egészből az a legfurcsább, hogy eredetileg a pythont találtam nagyon lassúnak.

----------------------------------------------------------
update: na ez egyre cifrább lesz. Kipróbáltam a korábbi tesztprogramokat úgy, hogy kihagytam belőlük a regex használatot, a futásidők elég közel kerültek egymáshoz. OK, tehát a regex lassít. Most csak a python-t és a java-t átírtam úgy, hogy két változóba beraktam egy-egy fix stringet, az egyik olyan, amire biztosan illeszkedik az előkészített minta, a másik meg olyan, amire biztosan nem és ezeket ellenőriztettem 10milliószor. Érdekes módon így szinte tizedmásodpercre egyforma időket kaptam a java-tól és a pythontól. Mindkettő 39-41 másodperces futásidőket produkál.
Persze sok aljasságot kinézek a regex feldolgozóból is. Például azt is, hogy cache-eli a mintákat (ha nem teszem ki külön compile-ba, akkor is csak egyszer fordít egy mintát - legalábbis egy darabig -, így azt sem tartom kizártnak, hogy a már feldolgozott stringeket is tárolja és ha úgy látja, hogy egyszer már feldolgozta, akkor csak a tárolt eredményt adja vissza, nem dolgozza fel újra.

update2: azt továbbra sem értem, hogy ha csak simán végigolvastattam a fájlt, akkor miért nem jelentkezett komolyabb eltérés, de tény: ha a python is soronként olvassa az inputot, akkor minimálisra csökken az előnye a többiekkel szemben.

Hozzászólások

Kezdésként ha nem mérnéd bele az interpreterek elindulását és leállását, biztosan teljesen más eredményt kapnál...
A programból mérd a futásidőt.
--
zsebHUP-ot használok!

+1 szerintem teszteld őket valami text manipuláción, ahol nem használsz beépített függvényt hanem te végzed el a műveletet ruby kóddal.

De egyébként az ilyen szintetikus teszt nem sokra lesz jó. Kicsit bonyolultabb problémán lenne érdemes tesztelni, de ott meg már meg kellene nézned a nyelv specifikus dolgokat, hogy melyik nyelvben mit lehet gyorsítani, mire van beépített függvény. És úgy lenne talán valamilyen szinten mérvadó a dolog szerintem.

Szerk.: Annyit még hozzáteszek, hogy pl. saját kódom (>25 ezer sor) rengeteg (több száz) SQL hívással, iszonyat sok text manipulációval lefut <0.1 sec alatt. Tiszta Ruby kód kiterjesztések nélkül. Szóval nem olyan lassú ám az, kérdés tényleg hogy mi a feladat és hogyan csinálod meg.

A nyelvek regexp feldolgozásának a sebességére voltam kíváncsi. Egy ebből a kifejezésből kialakult, sokszorosan bonyolultabb regexp volt az ötletadó, mert az akkori program, egy ekkora állományon kb. fél percig tökölődött.
De hacsak nincs valami trükk a javahoz, akkor maradok a pythonnál egyelőre. :)

Na... megjött a szakértő úr is.
Mi van, kompenzálsz, mert a héten párszor már beégtél?
Ahogy most is... mondjuk ahogy megszakértetted tegnap-tegnapelőtt a javat... ROTFL :D

Szerinted az ismételhetően azonos eredményeken (+/- pár százalék) mit befolyásol, hogy virtualizált környezetben fut? (különösen, hogy manapság lassan nem is találsz sehol fizikai vasat, max. VPS-t)

Java, C, ruby következetesen 3.5sec körüli időkkel fut. Ugyanott, ugyanazzal az inputtal a perl és a python 2sec alatt van bőven.
Következetesen, ismételhetően.

Nem ezred másodpercekről van szó.

Annyi helyem sajnos nincs. Esetleg megpróbálok valami pipe-ba adatot generáló szkriptet összehozni, de ezt nem ígérem meg.

Azt kipróbáltam (biztos ami biztos), hogy kizárólag CPU-t használó alkalmazásoknál nagyságrendekkel gyorsabb a java (ez nem lepett meg, eddig is tudtam), csak a regexp feldolgozás ilyen. Még csak nem is az I/O, mert ha kiveszem a programokból a szűrést, akkor kb. azonos időket futnak.

update: annyit tudtam tenni, hogy egy pipe-ba (mkfifo-val készült named pipe) tízszer egymás után beírtam az eredeti teszt állományt.
Így a python 22sec körüli időket fut, a java 38-40, a C 45.
(C-t csak egyszer néztem, a pythont és a javat 3-3 alkalommal egymás után)

> Ahogy most is... mondjuk ahogy megszakértetted tegnap-tegnapelőtt a javat... ROTFL :D
Nna, ki ne derüljön, hogy a Java igazából nincs is tele következetlenségekkel. "ROTFL".

> (különösen, hogy manapság lassan nem is találsz sehol fizikai vasat, max. VPS-t)
Mit tetszett mondani? He?

> c tovább fut, mint a python
Ez biztos? Mármint normálisan van megírva a program?

Hát egyre inkább azt látom, hogy szolgáltatóknál is a virtualizáció a jellemző, meg amit innen-onnan hallok a világba szétszóródott ex kollégáktól, sok helyen (szinte mindenhol, ahová van még kapcsolatom) erősen nyomatják a virtualizációt.

A C program sincs rendesebben megírva, mint a többi: http://pastebin.com/wWanjtWZ
Viszont olyan pici és a regex feldolgozó nélkül olyan gyors, hogy csak és kizárólag a regexec hívása lassíthatja.
A pcre egyelőre kimaradt, az valószínűleg jelentős gyorsulást okozna, de (feltételezem az eddigiek alapján), attól nem lesz annyival gyorsabb, hogy érdemes legyen elgondolkodni a python leváltásán, ha netán valaha elkészül a kis programom és hasznosnak is ítélem... :)

ui: azért azt te is érzékeled, hogy mekkora ökörség volt saxus részéről a virtualizáción élvezkedni, miközben harmincszor lefuttattam pythont is, javat is és mindannyiszor közel azonos eredményt kaptam... Ennél már csak az volt jobb, aki a forráskód miatt reklamált. :D

Baszki, te beszélsz beégésről, mikor azt sem tudod, hogy mit mérsz, mert tűtöriálokból ollózod össze?

"mondjuk ahogy megszakértetted tegnap-tegnapelőtt a javat... "

Bocsika, nem csak én mondom, hogy fos, hanem a Java tervezői (különben nem csináltak volna új API-t) illetve egy halom más ember (különben nem csináltak volna félcsilliárd alternatívát.)

"Nem ezred másodpercekről van szó."

Mert ugye olyat nem láttunk, hogy véletlenül mégis kicsit több CPU időt igényel magának a host os aztán valahogy mégis torzít az eredményen. Függetlenül attól, hogy mi hogy fut sok helyen.

De láthatóan szakember vagy, miután tutorialokból összeollózott kódokat próbálsz mérni, csak épp azt nem tudod, hogy mit.

Mellesleg nem tudom milyen beégésről magyarázol, mikor számtalanszor bebizonyíttat már, hogy halvány lila fingod nincs, hogy mihez szólsz hozzá, cserébe legalább bevágod a jópofit, ha esetleg "véletlen" mégsem jön össze. Esetleg talán nézz egy picit magadba is mielőtt megint előveszed a nagy pofát, mert kurvára unalmas ez a stílus, amit művelsz.

----------------
Lvl86 Troll, "hobbifejlesztő" - Think Wishfully™

Ennyi agyatlan ökörséget hogy tudsz összehordani?
Mert az nyilvánvaló, hogy fingod sincs arról, hogy mit mértem.
Szakértő úr... poliba több értelem szorult, mint beléd. :D
És ha legalább lefuttattad volna a mellékelt kódokat, óhajodnak megfelelően egy fizikai vason, ahol pontosan ugyanezt láttad volna... :D Mert azt kb sejtem, hogy mi fut épp a hoston, mivel itt van a gép a kezemben. De az a cuuuunya, gonosz vindóz hoszt mindig akkor fogja meg a cpu-t és a diszket, amikor szegény kis java, meg c, meg ruby futnak, hogy meghamisítsa a méréseket. :DDD
(Egyébként mivel láttam már csodákat, kipróbáltam virtualizáció nélkül is egy másik linuxon és pontosan ugyanezek jöttek ki, csak ezt nem kötöttem a taknyos orrodra)

Mondd, agyatlanka! Amikor az egyik 30, a másik 15mp-ig fut, akkor szerinted mi jelentősége van az interpreter pár század, esetleg tizedmásodperces indulási idejének?
Az I/O-nak még so so, lehetne hozzá köze, de ha kicsit figyelmesebben olvastál volna, regexp nélkül futtatva olyan gyorsan lefutott mind a java, mind a python, hogy nem volt valószínű, hogy az I/O bármit is befolyásol. (1-2mp vs 20-40mp)

És még most sem vagyok meggyőződve róla, hogy az olvasás lenne ennyire lassú a javaban, de inkább nem fárasztom magam veled.

Miután senki nem látta, hogy melyik tutorialból csórtad össze a dolgokat, elég nehéz megmondani, hogy mit csinál a kódod.

"nem volt valószínű, hogy az I/O bármit is befolyásol"

De, pl. egyik olvashat bufferelten, másik meg nem. Egyébként már eleve az toplel kategória, hogy regexp performancia esetén IO-ról beszélünk. Semmi köze a kettőnek egymáshoz.

"akkor szerinted mi jelentősége van az interpreter pár század, esetleg tizedmásodperces indulási idejének?"

Az, hogy semmi köze hozzá. Akármennyi is az eltérés.

----------------
Lvl86 Troll, "hobbifejlesztő" - Think Wishfully™

+1 a szakmai részhez

HZ, szerintem jogos saxus azon meglátása, hogy a VirtualBox-ban futtatás akár jelentősen is befolyásolhatja az eredményt.

Javasolt olvasmány: Dynamic recompilation
VirtualBox uses dynamic recompilation

Ezért én is úgy gondolom, hogy a teszteredményeid csak azt mutatják meg, hogy VirtualBox alatt milyenek a regex teljesítmények.

Nem. Akkor lenne jogos, ha
- ismeretlen szerveren tesztelek, nem a notebookomon (itt kb tudom, mennyire terhelt a host)
- ha csak egy, esetleg két futtatásból vonnék le következtetéseket (mostanáig 30-40 teszt futott, mindig hasonló eltéréssel és nem öt percen belül)
- ha nem ugyanezt kaptam volna fizikai vason is :D

a linked akár indokolhatná is az eltérést, de ugye kipróbáltam virtualizáció nélkül is.
Valami nagyon hülye dologba futottam bele: az I/O foghatja meg de ez valamiért csak akkor jelentkezik olyan mértékben, ami már feltűnő, amikor belekerül a regexp feldolgozása is.

saxus itt próbálja levezetni a frusztrációit, ezért ész nélkül vagdalkozik.

ui: dynamic recompilation téma egyébként kicsit meglepett. Qemu-ról és társairól tudtam, hogy csinálnak ilyesmit, virtulbox kapcsán kissé váratlan volt. De ahogy elnézem, ez csak dos jellegű rendszerek és a bios futtatása idején él, az én tesztjeimbe nem nagyon szól bele.

Javában nincs olyan, mint a .NET Regex.CompileToAssembly metódusa?
Gondolom, a Java is úgy csinálja, hogy string->tokenizált->bájtkód->natív.
.NET-ben a fenti metódussal dll-t fordíthatsz regexekből, ami már eleve a bájtkódot tartalmazza. Sőt, monóval fordíthatsz belőle végül eleve binárist is :)

Megtennéd, hogy az adatfile-t is felrakod valahova, amin tesztelsz?

http://stackoverflow.com/questions/180158/how-do-i-time-a-methods-execu…
Ennek alapján tettem bele belső mérést, ugyanúgy 3sec fölött van a futásidő.
És az sem változtatott rajta, hogy openjdk vagy oracle/sun.

Az inputnak meg nincs jelentősége (router log egyébként), mert fizikailag ugyanazon a fájlon futtatom őket.

Na ez viszont már a csúcs: megírtam (igaz, csak nagyjából, mert a zárójeles kifejezést nem bírtam beleerőszakolni) ugyanezt C-ben is az előbb, posix regex library-t használva.
Ugyanazt a sebességet hozza amit a java és a ruby.
A python és a perl kb. 3x gyorsabb e téren.

Ebből minden külön nyomozás nélkül is arra tippelek, hogy a python a perl libet használja, a többiek a posix-t. :)
(persze tévedhetek)

Az egész benchmark egyébként nagyon jó, az külön tetszik, hogy adott feladatra akár több algoritmust is bedobnak. Pl. a fannkuch-redux tesztnél volt egy java algoritmus,
ami 76 másodpercig futott, majd ezt megoptimalizálva sikerült olyat csinálni, ami 17 másodperc alatt lefutott. Vagy a PHP: 52 percről 12 percre sikerült letornázni.

Kiválóan mutatja, hogy nincs egy nyelv, ami mindig a leggyorsabb, illetve azt is érdekes megnézni, hogy mennyi kóddal lehet megoldani viszonylag jól egy problémát.

Köszönöm, ebből sokat lehetett tanulni.

Ez a mérés biztosan mér valamit, csak nem azt, amit a tárgyban írtál (Regex performance). A forráskódok ismerete nélkül pedig nem lehet válaszolni arra, hogy miért fut lassabban az L1 nevű izé a másik l1 nevű izénél.

Esetleg azért, mert
1. A ruby-t tutorialból kellett kibogarásznom
2. Eredendően nagyméretű logok feldolgozásának apropóján indult az egész, ami nem feltétlenül fér a memóriába.
3. Itt csak a sebességteszt kedvéért lett lecsupaszítva az eredeti kód, amit pythonban lassúnak találtam a regexp miatt. :)

Mellesleg a két sorod hogyan számolja meg, hogy hány sor illeszkedett a mintára és hány nem?

Egyébként látom beleástad azért magad Python-ba és látom hogy tetszik, de kicsit belemélyedhetnél Ruby-ba is, szerintem mindenképp hasznos lenne számodra.

Főleg az ilyen re.compile szörnyűségek elfelejtése sem lenne gond :)

Ruby-ban ennyi a regex:

"hello ez egy szöveg"[/myregex/]

vagy mint írtam valahol:

"hello szöveg".scan(/regex/)

Ez utóbbi egy tömböt ad vissza az összes találattal.

a = "hello ez a szövegem".scan(/regex/)
p a[0]
p a.size
p a

Jó, akkor ez a konkrét kérdésre választ ad, de az eredeti problémán nem igazán változtat: most csak egy ellenőrző műveletre volt szükség, hogy lássam, valóban felhasználja a mintát és megtalálja az illeszkedő sorokat.
Eredetileg ez úgy működne, hogy végigmegy a log sorain, a feldolgozott sorból előállít egy objektumot, ami a sorban lévő adatoktól függ. Lehet, hogy arra is van egyszerűbb mód (pythonban is), de egyelőre olvasható kódot akartam.
Ha adott funkciót akarok tesztelni, akkor az eltérő nyelveken a lehető legkevesebb eltéréssel kellene megvalósítani, hogy az eltérő elemek miatt ne lassuljon/gyorsuljon az egész.

Itt egyébként - a legújabb próbák után - el tudom képzelni, hogy a python, ha egy text fájl sorain megyek végig for-ral, akkor berántja a nagyját a memóriába és ezért tud annyival gyorsabb lenni. Viszont ennek ellentmond, hogy a regex-re hivatkozó sorok elhagyása után nem volt jelentős eltérés a különböző nyelvek közt.
Na jó, túl sokat ismétlem magam, megyek aludni. :)

Nálam is lassabnak tűnik a Ruby a Pythonnál (ruby 2.1.2, python 2.7.5, 64 bit):

ruby -e 'require "benchmark"; f = File.read "/tmp/test"; p Benchmark.realtime{ p f.scan(/a.*b.*c/).size }'

81761
2.195066139

time python -c 'import re; reg = re.compile("a.*b.*c"); f = open("/tmp/test","r").read(); w = reg.findall(f); print len(w)'
81761

real 0m0.698s
user 0m0.579s
sys 0m0.115s

Kb 3-szor gyorsabb (ráadásul így python-nál ugye nem csak a kód hanem a teljes runtime betöltést mértem). Kernel log-ra futtattam én is.

> A ruby-t tutorialból kellett kibogarásznom

És innentől lesz invalid az egész. Mondjuk, hogy pythonhoz értesz, a többihez nem, de akkor ne is várjunk releváns eredményeket. Persze lehet saxust ekézni, hogy ő nem ért hozzá, de benchmarkot csinálni olyan nyelven, amihez semmi közöm nincs, elég vidám ötlet.

Valahol félreérted az egészet, de nagyon.
Nem benchmarkot akartam csinálni.
Milliószor leírtam: összetákoltam valamit pythonban és feltűnt, hogy bizonyos, a re modul használatával járó műveletek iszonyatosan lelassítják a programot.
Ez volt hetekkel, tán hónapokkal ezelőtt.
Most meg eszembe jutott és elgondolkodtam, vajon mennyivel lehet gyorsabb egy java vagy egy ruby. És azt láttam, hogy nemhogy nem gyorsabb, hanem kifejezetten lassabban végzik el ugyanazt a feladatot.
És itt elkezdtem keresni, hogy miért.
De akárhol, akármit méregetek, folyton oda lyukadok ki, hogy a regexp feldolgozás valamiért jóval lassabban megy más nyelveken, míg pythonban, perlben hozzájuk képest gyors, az általam várthoz képest... hát nem annyira. :)
Egyébként perl-hez sem értek már sokkal többet, mint C-hez vagy java-hoz, az mégis messze a leggyorsabbnak jött ki.

saxus meg az utolsó hozzászólását leszámítva, csak kötekedni járt ide.

? mégis megismételhetnéd, mert ezt viszont nem értem. :)

Egyébként vevő vagyok minden ötletre, mert még mindig nem tudom elhinni, hogy akár java-ban, akár C-ben lassabban működne a regexp feldolgozás, mint egy perlben vagy pythonban.
(a ruby annyira nem izgat, az eleve két esélyes volt)

Első körben (Java) van a bufferedreader-nek olyan konstruktora, ahol megadhatod a méretet, azt próbálnám nagyra megadni.

Másrészt nekem a readline gyanús a Java kódban, inkább próbálkozz ezzel. Innen jutottam oda.

Fordítva nem ér?
Kiiktattam a regexp feldolgozást, úgy futtattam. Minimális az eltérés a java és a python közt, még akkor is, ha 10x annyi adatot olvas, pipe-on keresztül.

A poén, hogy valaki itt említette a pcre-t, azt is kipróbáltam C-vel, de semmivel sem gyorsabb, mint a posix-é. :)

No, engedve az erőszaknak...
Kicsit átírtam a java-ban elkövetett tesztet: http://pastebin.com/kgGuVzVM

Tehát most egyszer betöltöm egy tömbbe az egészet, annak megmérem az idejét, majd ezen a tömbön (ArrayList<String> valójában, de az eset szempontjából nincs jelentősége) végigmenve, csak annyit ellenőrizve, hogy az aktuális string illeszkedik-e a megadott mintára, még mindig ott tartok, hogy önmagában az illeszkedés vizsgálata tovább tart, mint ugyanezen a fájlon a python interpreter indítás, fájl végigolvasás, mintailleszkedés ellenőrzés összesen.
(java csak a regex az előre beolvasott listán: 2800-3000ms, python, I/O+regex együtt: 1700-1800ms)

Itt már gondot okoz, hogy nagyobb méretű fájlon futtassam, max. annyit tudok megtenni, hogy 10x futtatom a tesztelő ciklust, de feleslegesnek érzem.

Egy tippet kaptam (már nem tudom, hogy itt vagy máshol), amit nem tudom, hogyan ellenőrizhetnék: esetleg a python és a perl 8 biten dolgozik, a java meg unicode karakterekkel?
Hát ezen még dolgozom... :)
De ha van valakinek értelmes ötlete, ne kíméljen! (nem akarom elhinni, hogy tényleg ennyire lassú java-ban a regex... még a pythont is lassúnak találom :( )

Egyre érdekesebb ez a java vs python.
Ha a java-ban csak annyit módosítok, hogy a match() helyett find()-ot használok, még nincs érzékelhető változás a sebességben.
Viszont... ha ezt követően a minta végéről lecsapom a "(.*$)" karaktereket mind a python, mind a java kódban, akkor máris 50%-ot ráver a java a pythonra (persze csak akkor, ha memóriában tárolt sorokon mászok végig, ha a beolvasás idejét is hozzáveszem, még mindig a python nyer, de ez a része már nem izgalmas)

Na ezt magyarázza meg valaki! (ne azt, hogy miért gyorsabb, ha nincs a mintában a "sor végéig innen bármi lehet" minta, mert azt nagyjából tudom, hanem azt, hogy ezt miért lépi át gyorsabban a python, mint a java!)

Hát, őszintén, engem eléggé hidegen hagy, hogy egy adott regexp-nél most 2 másodperccel lassabb lesz. Vagy akár az összesnél. Ha annyira zavar, ott a forráskód, meg lehet nézni, ki lehet mérni, hogy hol és melyik rész a lassabb. Számomra ez tökéletesen megfelelő, ha neked nem, keress másik libary-t, vagy erre a feladatra válassz másik nyelvet.

Jó lenne azért tisztáznod már magadban, hogy mit mérsz. Sok vizet azért nem kavar a nyelv, ha nem a nyelven készült a lib. Példának okáért a Pythno-s regexp cucc is C-ben készült. (Majdnem meglepő módon...)

Másrészt Java-hoz is van bőven elég Regexp lib: http://tusker.org/regex/regex_benchmark.html

----------------
Lvl86 Troll, "hobbifejlesztő" - Think Wishfully™

Goto1: ha eredetileg, trollkodás helyett értelmezni próbáltad volna korábban amit írtam, akkor rájöhettél volna, hogy az egész mindössze abból indult, hogy valamit lassúnak találtam.
Megnéztem más, nyelven is, aminek minden épeszű számítás szerint gyorsabbnak kellett volna lennie és azt találtam, hogy sokkal lassabban fut le.
Ennyi.

Erre keres(t)em a magyarázatot. Akár azt, hogy hol cseszem el a mérést, akár azt, hogy miért megy lassabban a javas verzió.
Részben megvan a válasz: a .*-ot (vagy a .*$ kombót?) lassabban kezeli a java, mint a python.
Hogy miért? Ez továbbra is érdekelne (feltételezem, a "gyári" java regexp szintén C (v. a pythonos sem az), mert enélkül a .* minta nélkül egy nagyságrendet ráver a pythonra.

Azért az a táblázat nagyon durva, de okulva a mostani esetből, már fenntartással kezelem a futásidőket. :)

1. java futtató indítása sok idő
2. python cache-eli a regexp fordítást

Ne kezdjük ezt újra!
1. a java indítása tized, századmásodpercekben mérhető (ekkora program esetében, default paraméterekkel)
2. Programon belül is megmértem, hogy tömbön végigfuttatva, csak az adott regexp mennyi időt vesz igénybe a hétszázezer soron
3. Nem csak a python, de itt nem is a regexp fordítása volt a lassú, mert a compile cikluson kívül volt minden esetben.

/o\

Ez a thread nélkülöz mindenféle
- emberséget - össze-vissza sértegetitek egymást
- türelmet - a topiknyitó tutoriálok alapján írt kódot próbál benchmarkolni
- szakmai alázatot - nem is hajlandó a tévedését belátni és intelligensen nekiállni annak, amit akart volna
- tudást - a regex engine-ek közötti különbségekről és az egyes esetekről, mikor, melyik hogy szerepel
- mérnöki hozzáállást - méréselméletről nem is hallottak itt sokan.

Ez rossz. Ne értsetek félre, én sem tudnám helyesen benchmarkolni ezeket a motorokat, de lehet, hogy ha kéne - még csak a magam szórakoztátására is -, de szépen sorban mind az 5 felsorolt pontban cselekednék...

:-(

Te valamit félreértesz: nem általános benchmarkról van szó, pusztán egy véletlenül felfedezett, érthetetlen sebesség különbségnek próbáltam utánajárni.

Nincs mit belátni, mivel csak arra kerestem választ (hogy miért itt, az más kérdés - miután te már a sokadik vagy, aki meg sem próbálja megérteni, hogy mire voltam kíváncsi), hogy miért lehet egy python kód gyorsabb adott esetben egy java-nál, pláne C-nél.

Most te is bejöttél ide, megmondtad a frankót (bocs Gábor, nem személyeskedés! :DDD ), de semmit nem tettél hozzá a témához. Kérdem én: ezek után miben vagy több/jobb, mint bármelyik huptroll?

ui: ja, igen, regexp motorok... Ugye nem haragszol, hogy merészeltem kizárólag az adott nyelvekhez tartozó, "beépített" variációt használni - meg mellesleg, bár itt nem publikáltam, a gnu.regexp modult, ami a saxus által linkelt táblázat alapján sokkal gyorsabb, mint a java-é, nálam meg ugyanazzal a kifejezéssel, amit korábban használtam, sokszorosan lassúbbnak bizonyult.

Nem trolllkodni jöttem, hanem szólni (pontokba szedtem), hogy amit csináltok, az szakmai-emberi szempontból is színvonaltalan; én is sokszor belemegyek a sűrűjébe dolgoknak, és ha eldurvul a dolog, örülök, ha szólnak.

Ha neked ez nem tetszik/kell, sajnálom, azért megpróbáltam.

> semmit nem tettél hozzá a témához
Minimum annyit hozzátettem, hogy
1) vedd észre magad
2) érdemes lenne utánajárni a különböző regexp implementációknak
3) méréselméleti szempontból megnézni, mik vezethetik félre a kapott statisztikáidat.

Ha ebből csak az 1-es pontot felvennéd, szorulna belétek annyi tisztelet/szakmai alázat, amivel ebből a topikból valami hasznos is lenne.

A HUP nem a te játszótered, hanem mindenkié. Én most láttam úgy, hogy a homokozóba szarsz, gondoltam szólok, hogy mások is vannak itt.

Hmmmm... érdekes, hogy érdemi hozzászólásra még most sem vagy képes, csak önkéntes csendőrködésre. Na mindegy, felőlem gondolj amit akarsz, de ha érdemben képtelen vagy hozzászólni, akkor légy oly kedves és tartsd meg magadnak a véleményed, mert erre nem vagyok kíváncsi.

2. Hol érdekel engem, hogy hányféle implementáció milyen eredményeket ad, mikor kizárólag azon méláztam, hogy mitől ment lassabban egy interpreteres nyelven ugyanaz a feladvány, mint natív kódra fordítva. (ha egy kicsit még olvasgattál volna, akkor talán észre is veszed, hogy a mintának egyetlen aprócska részlete lassította le, ki tudja miért a java-t és feltételezem, ki nem próbáltam, a C-t is)

3. Nem vagyok mérnök, ezer bocs, hogy csak játszom ezekkel az eszközökkel, ugye azért még levegőt szabad vennem az engedélyed nélkül?

Hogy ki szarik a homokozóba, arról picit más a véleményünk.
Szerintem az, aki idejön arcoskodni, meg pofázni szakmai alázatról, miközben csak ködösít.

Azért vicces, hogy 5x éves korodig nem fogtad fel, hogy aki nem veled van, az nem feltétlen van ellened.

Vagy, hogy esetleg picit több segítséget kapnál, ha nem egyből visszatámadnál, mert valaki felhívja a figyelmed, hogy talán neked is van bőven vaj a füled mögött.

De úgy sem fogod megérteni.

----------------
Lvl86 Troll, "hobbifejlesztő" - Think Wishfully™

Trollócska: messze vagyok még az 5x-től, másrészt aki trollkodik, mint te is, az trollkodik és pont. Nem arról szól a dolog, hogy velem vagy ellenem, hanem arról, hogy felveszi a te stílusodat és egyáltalán nem a témáról ír.

ui: ha meg közmondásokat próbálsz idézni, legalább tanuld meg őket, mert ekkora fasságokat csak "panelproli" síkparasztok szoktak összehozni... :D
(gyk: vaj van a fején vs. valami van a füle mögött... :DDD)

Teljesen egyetértek, ezzel a hozzászólással. Kicsit olyan ez mintha valaki kenyeret akarna sütni, de nem rak bele élesztőt, hanem purhabbal helyettesíti, úgy gondolkodik, hogy a purhab megdagad akkor már helyettesítettem is az élesztőt. Persze jönnek a szakácsok, akik szólnak, hogy rakjál a purhab helyett élesztőt, és akkor minden jó lesz. Vagy ha mindenképp kísérletezni akarsz akkor használj olyan dolgokat, amikből főzni szoktak. Erre az a válasz hogy mindenki csak troll, aki nem mondja meg, hogy hogyan lehet purhabbal kenyeret készíteni. Egyébként is értek én a purhabhoz sokat használtam, kőműves vagyok, dagadni dagad, színe jó, kenyérnek is jó lesz. Sok munkával, és kísérletezéssel, el is készült a purhabos kenyér, kellett hozzá egy kis cement is, és máris jó lett. Ne mondja senki, hogy nem lehet megcsinálni, kész van lehet. A szakácsok mind hülyék. Csak valaki azt mondja meg miért olyan szar az íze?

B+, még hány ilyen önkéntes csendőr troll jön ide megmondani a tutit?

Aki érdemben nem tud hozzászólni a témához, miért épp itt sírja ki magából a bánatát, hogy nem akar offtopic-ot olvasni, de azért biztos ami biztos, ő is növeli a felesleges szófosás mennyiségét?
Ti észnél vagytok ilyenkor, úgy őszintén...
(igen, téged is trollnak tartalak, mint az összes önkéntes csendőrpalántát - különösen, hogy jó, ha kéthetente egyszer szólsz a fórumhoz az adatlapod szerint...)

Pontosan. Én is azért adtam fel, mert nem tudtam már szebben, érthetőbben elmagyarázni. Különösen frusztrálóak azok a "viták" (a szó pozitív, építő értelmében értve), ahol az egyik fél nem hajlandó érdemben reagálni érvekre. Hogy erre mi a legjobb megoldás, azt valószínűleg retorikával és pszichológiával foglalkozók ezrei kutatják. Idő hiányában én arra fallbackelek, hogy otthagyom az illetőt.

Ahogy már többször leírtam: önkéntes csendőrök és trollok véleménye eleve nem érdekel.
Az csak mellékszál, hogy a nagy optimalizálás közben azt hagyjátok figyelmen kívül, hogy engem a magyarázat érdekeelt volna elsősorban, nem az, hogy hogyan gyorsítsak az egészen.

Most félreteszem, hogy milyen a stílusod, és megpróbálok segíteni, bár lehet hogy nincs értelme, de lehet hogy másnak segít. Hozzáteszem a java-n kívül a többi részhez nem értek. Tényleg nem kell ahhoz mérnöknek lenni, hogy tudja és alkalmazza az ember a tudományos módszertant, ami nagyjából az alábbiakból áll:
1. Elmélet felállítása
2. Kísérlet megtervezése ami alátámasztja, vagy cáfolja az elméletet
3. kísérletezés, mérés, konklúzió levonása.

Rengeteg elméletet olvastam itt a fórumon, de még 12 évnyi java tapasztalattal sem mondanám azt látatlanban, hogy bármelyik jó, és igaz.
Tehát ha arra vagy kíváncsi miért és hol lassú a java akkor a legegyszerűbb, ha megméred, és bizonyítod, vagy cáfolod az itt felmerült elméleteket.
Minden 1.6 utáni jdk-ban van jvisualvm, ami tud kapcsolódni a futó java processhez, és ezzel meg tudod profile-olni az alkalmazást. Így ki fog derülni hol lassú, és mivel mennyi időt tölt a program.
Ezt a tanácsot tudja adni egy szakács, ha akarod megfogadod.

Egy megjegyzés, ami e problémánál lehet, hogy releváns, lehet, hogy nem.

Amikor ilyeneket írtál, hogy "de tény: ha a python is soronként olvassa az inputot, akkor minimálisra csökken az előnye a többiekkel szemben.", akkor eszembe jutott egy saját benchmark tapasztalatom.

Pár éve nagyon optimalizálnom kellett egy kódot, ami számdarálást végzett sok megabájtos tömbökön. A részletek itt nem fontosak, hisz a probléma jellege igen eltért, de a tanulság talán itt is releváns: Az olyan programok futásideje, amelyek a CPU cache méreténél sokkal nagyobb adatokon dolgoznak és egy-egy kiolvasott adattal kevés műveletet végeznek borzalmasan függ a CPU cache viselkedésétől, az adatok memóriában való elhelyezkedésétől és a program memória írás/olvasás műveleteinek sebességétől.

No, az persze nyilván mindenkinek triviális, hogy ha pl. soronként olvasok egy fájl be és minden beolvasás eredményét egy új malloc()-cal (nem C-ben mással) foglalt területre teszem le, ezekből listát csinálok, akkor egy jó fragmentálódott memóriát kell kezelnem, míg ha egyszerre egy nagy helyet foglalok a teljes fájltartalomnak és oda öntök mindent, akkor nem lesz fragmentálva a program által lefoglalt terület a RAM-ban. A fent idézett különbség a Python soronkénti/egybe beolvasása esetek között akár ebből is fakadhat. Nem tudom igazán, mert a Python lelki világát nem ismerem, de a jelenség nagyon ismerősen hangzott. Első pillanatban nem látszik, miért baj, ha a kezelt adattömb szét van forgácsolva a RAM-címeken, de ha a CPU szintjén nézzük, akkor érthető, miért kerül több időbe, ha hirtelen nagyon távoli területet kell beolvasni, aztán visszaugrani ide, stb.

Számtömbökkel végzett optimalizálási tapasztalataim szerint (ha cache-nél sokkal nagyobb adattömeg, olvasás után kevés, egyszerű művelet a sok adattal, ...) elvileg egyenértékű kódok is jelentős futásidő-különbséget adnak még egybefüggő memória-foglalás esetén is, ha az adott CPU-n az egyik algoritmus sok cache-miss-t generál. Ezeket az adott CPU igen mély ismerete nélkül előre látni nem lehet, így a szegény felhasználó/programozó előtt csak szerencse kérdésének tűnik, hogy egy adott implementáció egy adott CPU-n miért gyorsabb, mint a másik, holott akár assembly szinten is számolva azonos számú művelettel jutnak el az eredményig.

Na, ez így elég kusza lett, de ennek nagyrészt a helyhiány az oka, valójában jól utánajártam az ügynek. (pl. a pontosság kedvéért a Linux scheduler-je alól kivettem azokat a processzormagokat, melyeken benchmarkoltam, és ezeken csak a benchmark futott.)

Ami a sok dumám konklúziója: szerintem érdekes lenne megismételni a mérést egy teljesen más cache-architektúrájú rendszeren, no meg persze nemcsak Virtualboxban. Azt sejtem, hogy a végső, optimalizált változataid közti erőviszonyok ettől is függenek. Ha ez igaznak bizonyulna, akkor nem algoritmikus különbségek, a regex-motorok eltérései, stb. határozzák meg a vizsgált problémát teljesen, hanem a CPU-cache-RAM rendszer részletei is.

Lehet, hogy a poén kedvéért a windows-omra is visszarakom egy időre a java-t, mert már kezdek kíváncsi lenni a dologra.

Annyi azért hozzátartozik, hogy (írtam is valahol itt) kipróbáltam fizikailag létező gépen is, hasonló eredményekkel.

Ami a soronkénti olvasást illeti... nem tudom, pontosan mi történik, amikor a pythonban ilyet művelek:

with open("file.txt","r") as f:
    for rec in f:
        pass

Ami biztosnak látszik, hogy jóval gyorsabb, mint ez:

with open("file.txt","r") as f:
    rec=f.readline()
    while rec != "":
        pass
        rec=f.readline()

Ez utóbbi variáció esetében a teszthez használt állomány beolvasása csak alig valamivel volt gyorsabb, mint a javas verzió, míg az előbbit megközelíteni sem tudom mind a mai napig a java BufferedReader-ével. Ezért készítettem egy olyan verziót, ami az egész állományt tömbbe tölti és azon megy végig.
Persze, ezt okozhatja az op.rendszer cache műödése is, a virtualbox... hát az talán nem annyira, mert a fizikai gépen is ezt produkálta, ha jól emlékszem.

Ezt sejtettem, csak nem tudom, hogyan lehetne java-ban utánozni.
A BufferedReader-nek hiába adok a 8K-nál nagyobb bufferméretet, nem növeli jelentősen az olvasás sebességét.
(próbáltam csak kevéssel növelni, de próbáltam úgy is, hogy a komplett fájl beleférjen - ehhez persze a jre-nek kellett egy -Xms is, jókora memóriával)

Azt olvastam én is (ha jól látom a címből), de az utolsó válaszban ott a lényeg: valódi ekvivalens nincs. Van ByteArray*Stream, aminek viszont úgy láttam, nincs String-es megfelelője, ami viszont nekem kellene.
B verzió - miután nem ismerem a javat még mindig -, hogy valami egész más neve van. Esetleg a BufferedInputStream, amire a ByteArrayInputStream doksi is hivatkozik? (azt használtam és a leírás alapján úgy emlékszem, ez nagyjából arról szólhat, mint a neve alapján az a .net-es izé)

Miután ő csak gondolkodás nélkül fröcsög és nem is ért a javahoz, kénytelen vagyok minden ilyesmit ignorálni. :)

Ne zavarjon, hogy pont az IO függést tudod kikerülni azzal, hogy egy MemoryStream-ból olvasól (akármi is legyen a neve) és nem FileStreamból.

Ahhoz meg nem kell ismernem a teljes Java API-t, hogy tudjam, hogy mi a mögöttes logika. Egyébként azt hiszem, nem neked kellene pofázni a hozzáértésről, mikor bevallottad, hogy tutorialokból ollóztál össze valamit.

----------------
Lvl86 Troll, "hobbifejlesztő" - Think Wishfully™

Na és vajon mi lesz a gyorsabb Mr. Tutorial Expert, az, ami X. méretű bufferrel dolgozik és akkor olvas, amikor kifogy a bufferből (ami már helyből okoz egy iowaitet), vagy az, aminél előre betöltöd a RAM-ba az egészet és az egyetlen szűk keresztmetszet a memória sávszélessége? (Minden egyéb ugyanaz, mint a többinél.)

----------------
Lvl86 Troll, "hobbifejlesztő" - Think Wishfully™

Magyarul annyira fasz vagy, hogy kettő kibaszott szót nem vagy hajlandó beütni a Googleba, mondván MemoryStream Java, ami kidob neked mindjárt elsőnek egy ilyen linket, hogy http://stackoverflow.com/questions/8436688/memory-stream-in-java, ahol kb. az első kommentben benne van, hogy mi kell neked.

Magyarán van fogalmam (mert olyan nyelvet még nem láttam, amiben vannak Streamek, de nincs olyan, ami egy byte[] -öt képes Streamként reprezentálni), csak te vagy egy ostoba gyökér pöcsköszörű, aki ahelyett, hogy picit gondolkodna inkább egyből visszatámad.

Bocsánat, hogy mertem segíteni azzal, hogy mire keress rá és nem rágtam a szádba egyből, mert feltételeztem rólad annyit (bár utólag visszagondolva nem tudom mire), hogy képes leszel kettő szóra rákeresni.

----------------
Lvl86 Troll, "hobbifejlesztő" - Think Wishfully™

Gondolom, ha ugyanezt javaban írom és a while ciklus csak annyi, hogy

try {
//br = new BufferedReader(new FileReader(fileName));
br = new BufferedReader(new InputStreamReader(new FileInputStream(new File(fileName)), "ISO-8859-1"));
while( (nextRec=br.readLine()) != null){
}
br.close();
} catch(IOException ex) {

} finally {
}

akkor itt sincs sok tennivaló _elvileg_.

A python regexp engine C-ben van irva, es nem fut at a hasznalata a VM-en.

Köszi.
Mondjuk furcsa, mert a re modult használó programot "strace -eopen"-nel futtatva nem találok a kimenetben semmi olyat, ami külső modulra hivatkozna, holott az összes modul megnyitása látszani szokott benne.
Viszont így érthető, ha gyorsabb, mint a java...
Már feltéve, hogy a java.util.regex.* valóban tisztán javaban íródott.
Így viszont az nem tiszta, hogy a java miért lehet gyorsabb mégis, bizonyos esetekben. :)))

(az import _sre sort nem fedeztem fel korábban valamelyik python modulban)

Mert a java kód is binárissá fordítódik/optimalizálódik menet közben. Minél többször fut le egy rész, a jvm annál inkább kioptimalizálja. Ez a fajta dinamikus
optimalizáció hosszú távon futó alkalmazás esetén (és ez a java alkalmazások 99%-a) bizonyos helyzetekben gyorsabb kódot tud eredményezni, mint a statikusan
fordított.

Egyébként egy JVM mélyét is ismerő megerősíthetnék, hogy valóban csinál ilyen optimalizációt a JVM vagy csak az elméleti lehetősége megvan rá? Mert ezt az érvet sokszor halljuk a managelt nyelveknél, de pl. a CLR via C#-ban is annyit mondanak a .NET 4-ről, hogy elméletben képes lehetne rá, de nem teszi mert általában az is elég, amit most nyújt a CLR jittere.

----------------
Lvl86 Troll, "hobbifejlesztő" - Think Wishfully™

jó, most ez egy olyan nyúlfarknyi kód, ami alapján sok mindent nem lehet levonni. Pl. hogy a sum az most helyileg deklarált változó vagy member (utóbbi esetben nem hajítható ki).

Az egész példakód láthatóan a triviális ""propertyk"" optimalizálásáról szól. (Egyébként ilyenkor eszembe jut a Delphi féle property, ahol read/write-hez meg lehetett adni helyből egy adattagot és nem kellett setter/getter function/procedure-t írni, ha nem volt muszáj. (Mondjuk ez Delphiben főleg nem volt hátrány, lévén, hogy elég gépelős nyelv.)

----------------
Lvl86 Troll, "hobbifejlesztő" - Think Wishfully™

Nem annyira szégyen az. Ne felejtsük el, ezt a bájtkódot egy vm fogja futtatni szemben az objektkóddal. A vm pedig mindig az adott architektúrára próbálja optimalizálni a futtatást, ez is a JIT lényege. Pont, hogy az lenne a gond, ha túloptimalizálná fordításkor; ez azt jelentené, hogy vagy csak az adott platformra optimalizálna, vagy hatalmas futtathatót (bájtkódot) eredményezne, ami több platformon is optimalizált.

Persze a konkrét példa elég csúnya (sum = y + y;), de ahogyan már felettem is szóltak, ez csak egy háromsoros kiragadott példa, ne ez alapján ítéljük meg a fordítót.

BTW. a topikhoz visszatérve valószínűleg a .*$ miatti lassuláshoz nem az optimalizálónak van köze, hanem egyszerűen a regexp-feldolgozónak. Ehhez egy OFF, bár itt a sűűrűben elveszik: Miután 1 napot optimalizáltam egy mátrix-mátrix-vektor-szorzáson (saját csapat libjével, research projekt), elégedetten dőltem hátra. Majd átzárójeleztem, mátrix*(mátrix*vektor)-ra, és hirtelen töredék ideig tartott. Szó szerint: beÍrtam két zárójelet a C++ kódba :-) Szóval azóta először a módszerben keresem a hibát..

Ha még azt is leírnám amit tegnap találtam...
A java valami hihetetlen vad dolgokra képes.
Egyébként a lényeg már megvan. Már nem tudom, ki írta, de igaz: a python re moduljának érdemi része C-ben íródott, egy import felett ( import _sre) átsiklottam amikor ezt kerestem.
Hogy miért épp a .* lassítja le ennyire a java-t az ugyan érdekes, de ez már algoritmus kérdése és nem interpreter vs jit. (Python vsjava)

Ez igy ertekelhetetlen. 1s-3s koruli tartomanyba eso meres hibaszazaleka hatalmas.
Minden implementacioba rakjal meg egy ciklust, ami 100x lefuttatja. Igy egyreszt kiiktatod a startup idot, masreszt pontosabb lesz a meres, jobban tukrozi a valosagot.

Megtettem, az eltérés "statisztikai hibán" belül van.

A startup időket külön is megnéztem, elhanyagolható (konkrétan: belülről is mérem az időket), kivéve, ha a java-t -Xms2000m kapcsolóval indítom ( miözben 2G RAM-ja van a virtuális gépnek :D ).

Mindenféle, megideologizálható magyarázatokat találtam, de minél tovább nézegetem, annál zavarosabbá válik az egész.
Lásd: ha benne van a .*$, akkor a python sokkal gyorsabb, ha kiveszem, akkor már a java gyorsabb, de legalábbis azonos időt fut, ha kihagyom az I/O-t a játékból.

(mással már nem foglalkozom, egyébként is az volt a lényeg, hogy java-ban meg lehet-e írni gyorsabbra)