Adatokat szeretnék feldolgozni néhány millió soros textfile-okon. Az awk már majdnem jó, csak lassú. Meg nem tud bináris kimenetet - a printf("%c", x) nem az -, de ezt megoldottam azzal, hogy base64 kimenetet generálok, s egy base64 -id parancsba pipe-olom az outputot.
Gondoltam, legyen akkor mawk, mert az gyors. Ott nincs BEGINFILE, ENDFILE, de ezeket meg lehet ügyesen oldani. Hiányzik a switch case szerkezet, megoldottam ezt is if-fel. Amin viszont elbuktam, azok a bitműveletek. Nagyon hiányzik az lshift(), rshift(), and(), or(), xor(). Pedig ezek megléte nem lassítaná a mawk-t, hiszen csak függvények lennének. Akinek nem kell, nem hívja meg.
Természetesen meg tudtam írni ezeket a függvényeket, de lassú lesz, s pont az lenne a mawk értelme a gawk-val szemben, hogy gyors. Memória beáldozásával lehet gyorsítani, egész egyszerűen tömbbe letároltam két 8 bites operandusra az and() és or() függvények értékeit. De ez sem az igazi asszociatív, string indexelésű tömbök esetében.
Tudom, hogy ez az „akinek kalapácsa van, mindent szögnek néz” tankönyvi esete, de sok soros ASCII file feldolgozásáról nekem az awk jutott eszembe, ami egy eléggé gyors nyelv egyúttal. Hát az, csak ha sokat kell számolni, és több millió sort kell megenni, akkor azért már nem olyan gyors.
Az az érzésem, írhatom át az egészet C-re. :( Ott persze vacakolhatok a hibák elvarrásával, file megnyitással, lezárással, azzal, hogy erősen típusos a nyelv, deklarációkkal. Gyorsan szerettem volna eredményt.
- 435 megtekintés
Hozzászólások
A csoport neve az, hogy: Szkriptek: Python, Perl, Bash, ...
Esetleg probaltad a masikakkal? Pythonban eleg gyorsan lehet haladni, es tudom, hogy tud bitmuveleteket, mert szoktam hasznalni. A Perl meg direkt szovegfeldolgozasra van. Meg melletennem a PHP-t, eleg sokat hasznaltam ilyesmire (bar eredetileg webre szantak).
--
When you tear out a man's tongue, you are not proving him a liar, you're only telling the world that you fear what he might say. -George R.R. Martin
- A hozzászóláshoz be kell jelentkezni
Ezek közül régen PHP-t piszkáltam nem túl mélyen. Az első kérdés, hogy mennyire gyors? Igen, írtam olyan PHP scriptet, ami nem HTML-be volt ágyazva, hanem parncssorból indult. Itt az a fontos, hogy tudjak bináris műveleteket, maszkolásokat, shifteléseket végezni, legyen nagyon gyors, mert sok az adat - igaz, hogy ezek offline regisztrátumok, de megőszülök, mire végez -, s tudjon bináris file-t írni, olvasni, azt kezelni.
A gyengén típusosság, interpretált nyelv azért volna jó, mert a kísérlet tárgya épp a feldolgozó algoritmus keresése: valós mérési eredmények első lépésben történő feldolgozását követően mikor kapom a legjobb eredményeket úgy, hogy ez ráadásul a való életben valósidejű feldolgozás mellett működjön, tehát nem megy az a software-es gondolkodásmód, hogy memória és futásidő van bármennyi.
tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
A PHP ezeket, amiket akartál, speciel pont tudja, de pont a gyengén típusosságából eredő retardáltságai miatt ügyelni kell arra, hogy mielőtt műveletet végzel, biztosan castold az adatot arra a típusra, amilyenre kell. Pl.
$val = ((int)$strpart_x << 1) | ((int)$strpart_y & 0xa0);
Bináris fájlt is lehet kezelni benne, pl. byte-array-ként így lehet beolvasni:
<?php
$f = fopen($argv[1], "rb");
$data = unpack("N*", fread($f, filesize($argv[1])));
fclose($f);
echo 'Ez ' . ($data[1080] == 0x4d && $data[1081] == 0x2e && $data[1082] == 0x4b && $data[1083] == 0x2e ? '' : 'nem ') . ' egy ProTracker file.' . "\n";
- A hozzászóláshoz be kell jelentkezni
Na jó, de már itt is foglalkozni kell a file-ok kezelésével - ami azért nem olyan megterhelő -, akkor inkább nekiesek C-vel, az legalább gyors lesz.
tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
Van
file_get_contents
, meg
file_put_contents
, de az nem byte, hanem karaktertömbökkel dolgozik. Persze, ha tudod, hogy mit csinálsz, akkor azzal is tudsz bináris fájlokat túrni. De nem akarlak lebeszélni a C-s verzióról.
Viszont, ha mutatsz példát a feldolgozandó állományból, meg, hogy mit is szeretnél csinálni, akkor akár *AWK-kal, akár PHP-vel, akár egyébbel, de biztosan fogsz kapni valamilyen tippet.
- A hozzászóláshoz be kell jelentkezni
GNU gawk-val megcsináltam, meg tulajdonképpen mawk-val is, csak ez utóbbi nagyon sánta a bitenkénti műveletek hiánya miatt. C-ben elkezdtem csinálni, de ott meg néha zsong a fejem a háromszoros indirekciótól: char ***valami. Volt néhány segmentation fault, de igen alaposan végiggondoltam, mi hova mutat, s már jó a file input és paraméter split része. Azt is megtanultam, hogy nem lehet százezres, milliós nagyságrendben hívni a realloc() függvényt, gondolom, széttöredezik a foglalt RAM, de ez csak tipp. Szóval azt csinálom, hogy csak akkor hívok realloc()-ot, ha több hely kell. Ha kevesebb, akkor csak használom a már lefoglalt területet. Ezzel spórolok futásidőt, memóriát. A hibaüzenet egyébként corrupted size vs. prev_size volt.
tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
:-D
De azért jó úton haladsz!
Az awk, ha sok string műveletet használsz, akkor belefut a garbage collection-be, meg a paging növekedésébe. (Ez az információ még az upgrade után 75MHz POWER + 128MB ram időkből származik.)
Ilyenkor érdemes egy kicsit átfogalmazni a tennivalókat.
Manapság meg a néhány millió rekord első szottyra betölthető a memóriába. Rengeteget programoztam C-ben, 10-15M 40-50 mezős, változó mezőhosszú rekordokkal, de 20 év alatt egyszer sem volt szükségem a malloc() és tsaira. Szóval próbálj meg pic-ként programozni! ;)
Az esetek többségében elfelejtheted a string műveleteket is, mert sokkal tovább tartanak.
Egy egyszerű példa, ha irányítószámokkal kell dolgozni. A 4db karaktert elrakhatod stringként is, így plusz foglalás meg 5 karakter lesz belőle. Aztán összehasonlíthatod str[n]cmp() segítségével.
Hasonlóan felesleges gondolat az atoi() használata, hiszen utána sem lesz jobb a helyzet.
A legegyszerűbb, ha a helyén hagyod és 32 bites int vagy int*-ként használod. Ezzel egy nagyságreddel gyorsabb lesz a programnak ez a része.
- A hozzászóláshoz be kell jelentkezni
Azért foglalok dinamikusan memóriát, mert nem akarok felső becslést adni arra, hány mező lesz egy rekordban, miközben pontosan tudom, hogy ötnél több sose lesz, hiszen négysugaras az oszcilloszkóp, meg egy a timestamp. :D A másik ok pedig az, hogy ha használsz valamilyen glibc függvényt, pillanatok alatt ott találod magad, hogy dinamikusan foglal memóriát, amelybe beteszi az eredményt, s visszaadja annak pointerét, s majd neked kell felszabadítanod a helyet, ha nem akarsz memory leak-es programot írni. Aztán volt, amikor nem figyeltem, túlbuzgó voltam, elszállt double free, aborted, core dumped üzenettel. :)
tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni
Szia!
Mert több szálon/CPU-n kell futtatni.
Ez csak akkor működik persze, ha a logfile-ban lévő sorok függetlenek egymástól.
(Régen használtam ezt, de az mawk valami miatt nem volt jó).
apt-get install gawk
apt-get install parallel
cat logfile_in.log | parallel --will-cite --gnu --keep-order --pipe 'awk -f file.awk' > logfile_out.log
file.awk
BEGIN {
IGNORECASE=1;
}
{
...
}
END {
}
- A hozzászóláshoz be kell jelentkezni
Gondoltam erre is, a parallelt más környezetben már használtam. Az a baj, hogy nem független, néhány rekordnyi távolságra el kell látnom, s ez probléma a file-ok határainál.
tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE
- A hozzászóláshoz be kell jelentkezni