Csatlakozott:2020.05.14. 11:32 Hozzászólások:165 Megköszönt másnak:14 alkalommal Megköszönték neki:63 alkalommal
[Előzetes] Az AMXX Pawn-ban minden változó 4 bájtot, azaz 32 bitet foglal. Egy plugin által lefoglalt memóriaterületet az 1.6-nak létrehozott (virtuális) memóriatér kezeli, ami több részre oszlik fel: stack (verem), heap(kupac), adat- és kódszegmens (utóbbi számunkra irreleváns). Ezekbe nem megyek bele mélyen, mivel külön topicot kellene rá szentelni és szeretném ezt a posztot hibridnek tartani, hogy érthető legyen kezdő/haladó fejlesztőnek is.
Habár játékos ma már kevésbé, régi/új fejlesztők fel-fel bukkannak időnként, most pláne a mestint miatt, és mivel sokakat láttam használni (vagy akár teljes kódot megírni ) úgy láttam nem ártana lebutítva egy gyorstalpalót adni a hatékony kódolásról, mivel rengeteg kódon akad meg a szemem, és vannak nagyon súlyos esetek is. Ha más nem, legalább ezt be lehet linkelni az AI-nak hogy ez alapján dolgozzon.
A tutorial alatt egy példakóddal fogok szemléltetni minden problémát és megoldást, hogy egyértelműen követhető legyen a nyavajgásom.
Ez a direkt(!) csonkított kód, ahol nincs userid kezelés, sql betöltés, mentés, beszúrás hogy könnyebben átláthatóbb legyen a tutorial érdekében, Egy egyszerű szintrendszert valósít meg. new userxp[33] -> A user xp-t tárolja new userlevel[33] -> user szintet tárol new bool:uservip[33] -> azt nézi, hogy a játékos beírt-e egy "titkos" parancsot, mely segítségével nem csak akkor kap xp-t ha valakit megöl, de akkor is ha valakit fejbe talál. 1 sql utasítás van a plugin_cfg-ben, ami létrehozza a táblát.
Ha valaki szintet lép, azt kiírja a plugin a chatre amit mindenki lát.
I. Memóriafoglalás (Static, New, méret)
Azért kezdem ezzel, mert tapasztalat szerint ez a legsúlyosabb mindközül.
Itt azt mondjuk a fordítónak, hogy: "Itt egy változó. Ezt tartsd készenlétben a plugin teljes életciklusa alatt."
Miért teljes életciklus? Mert a static/globális változók az adatszegmensben tárolódnak, azaz nem időszakosan jönnek elő a new-al ellentétben.
Mi ennek az eredménye?
A Query változó 10048*4 bájtot foglal egy függvényben. Mivel én ezt használom SQL adatbeszúrásnál, létrehozásnál, mentésnél és betöltésnél is (azaz összesen 4x), kumulálva 160,768B van felhasználva a plugin teljes futása alatt.
Holott, ha egyszerűen new-t használnánk minden alkalommal nem lenne ennyi nyomás alatt a szerverünk a korlátozott memória miatt. ILLETVE.
A tömbméret sem mindegy. Ez a static Query[10048] egy vírusként terjed az egész fórumon. Szinte mindenhol látom, nem lehet menekülni előle.
A 10048 helyett adjuk meg egy méretet a Queryként átadott parancsunknak a karakterszámát + még várható input karakterszámot véve, pl.: steamid. Jelen esetben:
"CREATE TABLE IF NOT EXISTS \\`szintrendszerxp\\`"+"\\`id\\` INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,"+"\\`steamid\\` varchar(32) NOT NULL, "+ \\`Lvl\\` int(11) NOT NULL," + \\`Xp\\` int(11) NOT NULL"-> ~200 karakter (ctrl c + ctrl v egy character counter oldalra)
ebből kifolyólag, legyen a tömbünk mérete 300 (200+steamid karakterszám+x számjegyű id + x számjegyű xp + x számjegyű szint) körül.
Most 1200 bájtot foglalunk összesen, amit ráadásul nem is végig veszünk használatba hanem csak időszakosan.
Ez azt jelenti, hogy 159,568B memóriát spóroltunk meg. Százharmincháromszorosára (!!) csökkentettük a memóriahasználatot.
Fontos: mivel ha new-al létrehozunk egy változót, az bekerül a stackbe, majd nullázódik. Ez 1 cellánál egyszerű művelet. Viszont ha már nagyobb tömbökkel dolgozunk, sűrűn használjuk, akkor mindenképp érdemes static-al deklarálni.
Tehát: - static: érdemes akkor használni, ha 1 másodperc alatt sokszor vesszük igénybe a változót ÉS nagyobb tömbről beszélünk. - new: minden más esetben
#define LVL_UP_TEXT "%s szintet lépett! Új szintje: %d"
Ezzel az a probléma, hogy a #define több műveletet igényel, mintha const-ként definiálnánk a változót.
A #define minden meghívásnál rátesz a stackre egy copy-t belőle. A const egyszer kerül be a heapbe, és onnantól kezdve a referenciáját kezeli a plugin.
Ez miért jobb? Leginkább olvashatóság és skálázhatóság szempontjából. Elég annyit látnom, hogy IsPlayer, akkor fogom tudni hogy mit jelent, és még könnyen is tudom változtatni az implementációját is.
Fontos tudni, hogy amíg erre mondjuk egy stock függvényt hoztunk volna létre (ami tárolódik is a veremben) addig a makrókat a preprocessor dolgozza fel és csak a kódszegmens méretét növeli.
A %0 paraméterként várja a bejövendő argumentumokat, és azokkal végez behelyettesítéses számolást.
Ez alapjáraton egy szép megoldás. Viszont a legtöbb alkalommal 5 ellenőrzést hajtok végre, és ráadásul egy Ham_TraceAttack_Post-ban, ami lövésenként lefut.
Makrókkal sokkal optimálisabb és szebb dolgozni. Valamint, így csak 1 ellenőrzés lesz végrehajva 5 helyett. Azaz, ötödére csökkentettük a számítást.
Viszont fontos megjegyezni, hogy a makrók nem mindig a legjobb választás. Ez most egy tökéletes példa rá, hogy sokkal optimálisabban jövünk ki 2 sorral, mint 10-el.
Hacsak nincs úgynevezett branchelés (if-else elágazás, switch, ciklus) a függvényünkben, érdemes lehet elgondolkodni rajta.
(Habár bőven elhanyagolható, szemfülesek észrevehetik hogy ez alapjaiban rossz, mivel 33 elemű tömböt hozunk létre 32 játékosra. Persze, ezt az egyszerű indexelés végett csináljuk így (én is így használom).)
Viszont most ott járunk, hogy 132 bájt van lefoglalva a memóriában.
Ennek a segítségével a kód több pontján is meghívhatjuk ugyanazt a folyamatot. Ha változtatni szeretnénk rajta, akkor csak ebben az eljárásban kell azt elvégeznünk. Csökkentett és skálázhatóbb lett a kódunk.
public TableCreateCallback(iFailState, Handle:hQuery, szError[], iErrCode, szData[], iDataSize, Float:fQueueTime){
if(iErrCode)
log_amx("[SQL HIBA] %s", szError)
if(iFailState ==TQUERY_CONNECT_FAILED)
set_fail_state("SQL Connection Failed")
elseif(iFailState ==TQUERY_QUERY_FAILED)
set_fail_state("SQL Query Failed")
}
Trie vs Array:
Ebbe nem megyek bele, mert sokkal nehezebb leegyszerűsíteni mint a többit, valamint nem férne bele ennek a posztnak a scopejába. Röviden: - Trie-t érdemes használni, ha stringeket tárolunk - Trie-ba könnyebb keresgélni. Vannak jó use-casek, pl. prefix használat chatbe, mute rendszer, stb. - Többi usecase dynamic array. - Mindkettő gyorsan olvas, viszont lassan ír
Jelenlévő fórumozók: nincs regisztrált felhasználó valamint 1 vendég
Nyithatsz új témákat ebben a fórumban. Válaszolhatsz egy témára ebben a fórumban. Nem szerkesztheted a hozzászólásaidat ebben a fórumban. Nem törölheted a hozzászólásaidat ebben a fórumban. Nem küldhetsz csatolmányokat ebben a fórumban.