Shery és RePa

2010. november 26.

jsmap.html

dyuri @ 10:20:55

Pár napja elkezdtem csinálgatni egy kis javascript alkalmazást, amely Icesus térképét jeleníti meg ASCII formában, forrásként a png alapú térképet használva. Eddig a dolog szerver oldalon futott le, és neten tolta át a több megás generált html-t, első körben ezt a folyamatot akartam felgyorsítani, de később tervezek bele egyéb feature-öket is, mint pl. hely keresés, vagy tagelés. Az első verzió igen lassú volt, azóta picit finomítottam rajta, és kíváncsiságból összehasonlítottam a gépeimen lévő böngészőkben mennyi idő alatt fut le.

Az induló böngészők a jelenlegi legfrissebb stabil verziók, ahol van <canvas> támogatás (tehát az IE kiesett).

A gépek, amiken a tesztet futtattam:
Linux: az otthoni gépem, 64 bites Arch Linux, AMD X2 BE-2100 (2.1Ghz)
Windows: a munkahelyi gépem, 32 bites Windows 7, Intel Core2 Duo E7500 (2.93 Ghz)
Minden böngészőn 5-ször futtattam le a tesztet (shift+reload) és a középső értéket vettem. (Egyébként a szórás elég kicsi volt.)

Íme az eredmények:

  • Chromium@Linux (7.0.517.43) - 492 ms
  • Firefox@Linux (Namoroka, 3.6.12) - 5082 ms
  • Chrome@Windows (7.0.517.44) - 538 ms
  • Firefox@Windows (3.6.12) - 2269 ms
  • Opera@Windows (10.63) - 863 ms
  • Safari@Windows (5.0.3) - 755 ms

A számok alapján a javascript futtatásban az egyértelmű győztes a Chrome, mindkét platformon ő volt a leggyorsabb, és Linuxon elvileg gyorsabb, mint Windowson (pedig az otthoni gépem lassabb, a firefoxos eredményeken valószínűleg ez látható), de sem az Opera, sem a Safari nincsenek nagyon lemaradva, sőt érzésre az Opera tűnik a leggyorsabbnak, mert míg a többi böngésző egyben próbálja kirenderelni a nagy generált html-t a js lefutása után, addig az Opera ezt valahogy folyamatosan teszi, és ezért kb. azonnal látjuk az eredményt. A Firefox meg rondán le van maradva egyelőre, remélhetőleg majd a 4-es behoz valamit. Na meg az IE9.

2010. július 27.

DjangoHU

dyuri @ 21:38:04

Pénteken megnéztük az Eredet (Inception) c. filmet, kifejezetten tetszett, na nem mondom, hogy szuper váratlan volt minden fordulat, de akkor is, jó volt. Nézze meg, aki teheti.

Csykin nemrég megszerezte a django.hu domaint, kicsit fel szeretnénk hypeolni itthon is a djangót, illetve a pythont, úgyhogy a szakmaibb postjaim ezután inkább oda mennek, itt is az első komolyabb hangvételű, a singletonokról.

2009. november 26.

Python, hogyanne

dyuri @ 16:02:28

Tök jó, hogy van pythonban pl. operátor overloading - én legalábbis szeretem, DE:

TM = list
class MyList(TM):
  def __add__(self, a):
    return [self[a[0]]]
 
>>> a = MyList([1,2,3,4,5])
>>> isinstance(a, list)
True
>>> a + [1] # ez lista osszefuzes lenne
[2]

Ilyesmit azért illetlenség csinálni, randa dolgokat eredményezhet, ha egy olyan függvénynek adunk egy ilyen objektumot, ami listát vár. Persze ennek a fordítottja is igaz, és nem csak elrontani tudunk így dolgokat, de megszépíteni is.
Az Class(TM) élő példa, bitbucketen láttam valahol :)

2009. szeptember 16.

libevent + tornado

dyuri @ 9:22:57

Úgy kezdődött a dolog, hogy a facebookos srácok nyílt forrásúvá tették és kiadták a FriendFeed mögött álló python alapú webszervert, a Tornadot. Aranyos dolog, mert nem blokkol, sok klienst képes párhuzamosan kiszolgálni és relatíve gyors mert esemény vezérelt. Feltéve, hogy Linuxon használjuk, mert csak és kizárólag az epollt támogatja (illetve a hagyományos select()-et, nade akkor oda minden előnye).
Viszont én Solaris alatt is szeretném kihasználni a fent említett előnyöket, úgyhogy gyorsan összedobtam egy apró wrappert a libevent köré, ami működik is, és így a Solaris/FreeBSD felhasználók is örülhetnek.

Gyorsan nézzük hogyan történt a dolog.

Először a libeventet kellett letölteni és lefordítani. Szerencsére gond nélkül fordult update 7-es Solaris 10-en.
(jelenleg az 1.4.12-es változat a stabil, azt használtam)

$ ./configure --prefix=/opt/bitnet
...
checking port.h usability... yes # solaris event ports, ez kell nekünk
...
$ make install

Hogy python alól használni tudjuk, ahhoz szükségünk van a python-libevent csomagra, amit én kézzel tettem fel innen, mert a sajtboltos változat ősrégi.

$ export CFLAGS="-I/opt/bitnet/include"
$ export LDFLAGS="-L/opt/bitnet/lib"
$ python setup.py install

Ezután jött az érdemi munka, a tornadot rábeszélni, hogy a libevent-et használja. Ehhez egy ugyan olyan wrapper osztályt csináltam, amit a srácok csináltak maguknak a saját epoll, illetve a hagyományos select() támogatásához, ami igazából a standard python Poll objektum által megvalósított interface:

class _LibEvent(object):
    """A libevent based IOLoop implementation"""
 
    def __init__(self):
        self._eb = libevent.EventBase()
        self._events = {}
        self._ready_fds = {}
 
    def _fd_ready(self, fd, events, eventObj):
        eventmask = (IOLoop.READ * (events & libevent.EV_READ) / libevent.EV_READ) | \
                    (IOLoop.WRITE * (events & libevent.EV_WRITE) / libevent.EV_WRITE) | \
                    (IOLoop.ERROR * (events & libevent.EV_TIMEOUT) / libevent.EV_TIMEOUT)
 
        self._ready_fds[fd] = eventmask
 
    def register(self, fd, events):
        # ezt a reszt is at lehetne alakitani olyanna, mint az elozo fuggveny
        eventmask = 0
        if events & IOLoop.READ:
            eventmask = eventmask | libevent.EV_READ | libevent.EV_PERSIST
        if events & IOLoop.WRITE:
            eventmask = eventmask | libevent.EV_WRITE
        if events & IOLoop.ERROR:
            # does libevent has error event type?
            eventmask = eventmask | libevent.EV_TIMEOUT
 
        self._events[fd] = self._eb.create_event(fd, eventmask, self._fd_ready)
        self._events[fd].add_to_loop()
 
    def modify(self, fd, events):
        self.unregister(fd)
        self.register(fd, events)
 
    def unregister(self, fd):
        self._events[fd].remove_from_loop()
        del self._events[fd]
 
    def poll(self, timeout=10):
        self._ready_fds = {}
 
        self._eb.loop_exit(timeout)
        # libevent.EVLOOP_NONBLOCK hasznalatakor a timert sem varja meg, es megeszi a cpu-t
        self._eb.loop(libevent.EVLOOP_ONCE)
 
        return self._ready_fds.items()
 
...
 
# legvegere, illetve a mar ott levo 'try' blockba:
try:
    import libevent
    _poll = _LibEvent
except:
    _poll = _Select

Illetve ha nem akarjuk belehackolni a tornadoba a cuccot, akkor "monkey patching" technikával is bedolgozhatjuk, ekkor az alkalmazásunk ioloopjanak indítása előtt kell megmondanunk explicite, hogy libeventet használjon:

import tornado.ioloop
tornado.ioloop._poll = _LibEvent
tornado.ioloop.IOLoop.instance().start()

(remélem ezt nem kell sokáig megtenni, jeleztem a fejlesztők felé, hogy jó lenne a libevent támogatást a fő fejlesztési vonalon látni)

Csináltam is néhány gyorstesztet az egyik szerverünkön, sok párhuzamos kérés esetén látszik a fejlődés. A teszteket az apache féle ab paranccsal mértem, ahol az 'n' az összes lekérés, a 'c' pedig a konkurenciát (ennyi szálon próbálkozik párhuzamosan) jelenti. A parancsokat háromszor egymás után megismételtem, és a legjobb eredmény került ki ide.
(ulimit -n unlimited)

  1. _Select:
    • n=10000, c=100: 1048.10 [#/sec]
    • n=10000, c=1000: 683.96 [#/sec]
    • n=10000, c=2000: 672.85 [#/sec] (a háromból egyszer meghalt a lenti hibával)
    • n=10000, c=5000: háromszor egymás után: filedescriptor out of range in select()
  2. _LibEvent:
    • n=10000, c=100: 1056.57 [#/sec]
    • n=10000, c=1000: 1013.59 [#/sec]
    • n=10000, c=2000: 1004.94 [#/sec]
    • n=10000, c=5000: 954.52 [#/sec]
    • n=10000, c=10000: 781.10 [#/sec]
    • n=20000, c=10000: 934.32 [#/sec]

Első körben nekem elég is volt ennyi, hogy lássam, hogy megérte, aztán majd valami egyszerű webalkalmazással meg kéne nézni, hogy a többi megoldáshoz képest (fcgi, cherrypy, esetleg mod_wsgi) hogy muzsikál a cucc.

Használjátok egészséggel!

2009. július 23.

bible.py

dyuri @ 9:58:57

Hiánypótló alkalmazással szeretnék előrukkolni, íme a bible.py.

Gondolom már sokatokban felmerült, hogy számítógépen olvasgatnátok a Bibliából, hát itt a lehetőség. A csomag tartalmaz egy sqlite filet, amiben a Biblia található meg soronként magyar és angol nyelven.
(Struktúra: id, könyv, fejezet, sor, nyelv, maga a szöveg)

Összedobtam hozzá egy olvasót pythonban - SQLAlchemy kell neki -, amivel gyorsan idézhetünk, ha kedvünk tartja. Persze az "API" közel sem teljes, de kiindulásnak jó, és igen könnyen lehet belőle webes alkalmazást csinálni.

Használat:

# egy sor
$ ./bible.py mt 13:4
Mert Isten szolgája õ a te javadra. Ha pedig a gonoszt cselekszed, félj: mert nem ok nélkül viseli a fegyvert: mert Isten szolgája, bosszúálló a haragra annak, a ki gonoszt cselekszik.
# több sor, angolul
$ ./bible.py mt 5:3-6 en
Blessed are the poor in spirit: for theirs is the kingdom of heaven.
Blessed are they that mourn: for they shall be comforted.
Blessed are the meek: for they shall inherit the earth.
Blessed are they which do hunger and thirst after righteousness: for they shall be filled.

Használjátok egészséggel, illetve ha valami hasznosat tesztek a kódhoz, küldjétek vissza, és kiteszem azt is.

2008. december 4.

Python 3000 is out

dyuri @ 10:33:17

Megjelent a végleges python 3000!
(Túl sok változás nem történt az előző postjaim óta.)

Pythonra fel!

2008. október 27.

mudlogger.py

dyuri @ 12:41:32

Ugye egy ideje már mudozok, aztán felmerült bennem, hogy néha logolni kéne a történéseket, megmutatni másoknak, vagy csak visszanézni, ha valami komolyban vettem részt. A tf tud logolni, de csak plain textben, azaz elvesznek a színek, és eléggé nehezen lesz áttekinthető a dolog.

Múlt héten, hogy pihentem, írtam egy kicsi scriptet (python ofc) [mudlogger.py], amit proxyként használva az szépen menti a teljes forgalmat. Ezután csak egy másik script kellett [logreader.py], ami az ANSI "formátumot" HTML-é konvertálja.

Példa kimenet. Az ogre kovácsot kérem meg finoman, hogy pihenjen.

Természetesen nem csak mud forgalom logolására képes a cucc, használjátok egészséggel.

2008. október 2.

Python 2.6

dyuri @ 15:20:08

Megjelent.

Elérhető benne szinte minden, ami a 3.0-ban benne lesz, csak még kompatibilis a régi verziókkal.
Amit most így hirtelen kiemelnék az újdonságok közül az a multiprocessing modul, és mostmár alapból jön a pythonnal json modul is. Illetve hát a dokumentációt is szép színes-szagos köntösben olvashatjuk (a Sphinx project jóvoltából).

Mindjárt itt a 3.0 is!

2008. július 25.

Py3k snippets – typecheck

dyuri @ 16:33:48

A python 3.0-ban jelennek meg a függvény argumentum megjegyzések (annotations, nemtom minek lehetne értelmesen fordítani), ami amellett, hogy dokumentációs célokat szolgál, segítségével megvalósítható python alatt is a függvény paraméterek típusellenőrzése (mert az egyébként nincs).

Maga az ellenőrzés nem lesz része a python 3.0-nak, és mindenhol azt írják, hogy egyszerű megcsinálni, de mivel sehol sem találtam meg, ezért megcsináltam magam. És valóban, egy egyszerű dekorátor függvény teszi, ami nekünk kell:

import inspect
 
def typecheck(func):
  def inner(*args, **kwargs):
    # check *args
    valueiter = iter(func.__annotations__.values())
    for arg in args:
      argclass = next(valueiter)
      if not inspect.isclass(argclass):
        continue
      if not issubclass(arg.__class__, argclass):
        raise TypeError("Hibas bejovo parameter!")
    # check **kwargs
    for arg in kwargs:
      if not arg in func.__annotations__ or not inspect.isclass(func.__annotations__[arg]):
        continue
      if not issubclass(kwargs[arg].__class__, func.__annotations__[arg]):
        raise TypeError("Hibas bejovo parameter!")
    # call the function
    return func(*args, **kwargs)
  return inner

Nézzük működés közben:

@typecheck
def a(alma: int, beka: str = "szia", mokus: int = 2):
  print(alma, beka, mokus)
 
>>> a(1, mokus=10)
1 szia 10
>>> a(1, mokus=10, beka=3)
Traceback (most recent call last):
  File "stdin", line 1, in module
  File "stdin", line 16, in inner
TypeError: Hibas bejovo parameter!
>>> a(1, beka="hello")
1 hello 2

Persze ez csak egy gyors megoldás, érdemes lenne a hibaüzenetben kiírni, hogy melyik paraméter hibás, ezt az érdeklődők megírhatják kommentben. :)

Pythonra fel!

2008. július 16.

Python 3.0

dyuri @ 8:31:35

Nemrég, hogy megjelent a python 3.0 beta (sőt, lassan itt a beta 2), úgy gondoltam, hogy megnézem mostmár mit tud. Eddig is olvasgattam, hogy a 2.x vonalhoz képest bizony változik az API, bár mivel a 2-es vonal is folytatódik, és több dologgal is segítik az áttérést, túl nagy gondok valószínűleg nem lesznek. A python 2.6 képes (lesz majd) jelezni, ha nem 3.0 kompatibilis dolgokat használ az ember, és ha már csak azokat használ, akkor van egy tool - a 2to3 -, ami az esetek 99%-ában automatikusan átalakítja a forrás py3k kompatibilissé.

Na nézzük röviden mit kapunk. tovább...

2007. november 13.

django.http.HttpFileResponse

dyuri @ 19:03:21

Egyik futo projectben felmerult, hogy hogy osztunk meg weben tartalmat ugy a neppel, hogy rendes access controlunk lehessen. Azaz pl. lehessen alligatni userenkent savszelesseget, hozzaferesi idot, es minden butasagot, ami csak eszunkbe jut.

Alapbol ugye van a webszerver oldali .htaccess es baratai megoldas, ahol eleg szukosek a lehetosegek, es hat nem is egy olyan kifinomult admin feluletunk van, mint a djangonak. De kigondoltam valamit, igaz a modszer nem tul hatekony - az eroforrasok szempontjabol -, de mindent lehet, amit mi akarunk, es majd max kap a gep +10% procit es memoriat.

Az alapotlet az, hogy nem kozvetlen a webszerver adja vissza a filet a kliensnek, hanem az csak egy cgi/fcgi scripttol keri azt el, ami szepen "felolvassa" azt a merevlemezrol, felteve, hogy a felhasznalonak ezt mi megengedtuk.
Ezt egyebkent egy akarmilyen scriptnyelvben nevetsegesen egyszeru megcsinalni, pl. phpban:

$filename = "/ez/a/file/kell";
header('Content-Type: ilyentipusuafile');
header('Content-Length: afilehossza');
readfile($filename);

Szoval egyatalan nem bonyolult.

Djangoban azonban nem talaltam olyat, hogyan adok vissza nem tipikus tartalmat. Az alap HttpResponse-t nem arra talaltak ki, hogy szepen olvassa fel a fileokat a winyorol, ugyhogy - eljen az OOP - leszarmaztattam belole, es ime az eredmeny.
Djangoban ezutan csak egy view kell, ami ellenorzi, hogy megfelelo-e minden feltetel (be van-e lepve a felhasznalo, a megadott idopontban tolthet-e le, kek-e a szeme, es hithu kereszteny-e), es ha igen, akkor egy egyszeru return HttpFileResponse(fileneve), es a file mar uton is van.

Nincs meg kesz persze, de akinek kell, az vigye, akinek meg van valami jo otlete, az szoljon! (A kod egyebkent a kb. 3 hettel ezelotti svn trunk alapjan keszult, stabil 0.96-os djangoval, vagy a legfrissebb fejlszetoi anyaggal nem feltetlen mukodik, de sokat tuti nem kell rajta dolgozni, hogy menjen.)

2007. október 9.

Kiegeszites: a kodblokkok szemantikus formazottsagarol…

dyuri @ 18:41:32

Gabor irt par gondolatot a programkodok formazasarol, hogy tabbal-e vagy space-szel, illetve mikor hogy.
Amellett, hogy azzal egyetertek, hogy mindegy, hogy mivel (en szpeszezek; et, ts=2), de valamivel mindenkeppen! Es ne keverjuk, hogy a kod elejen 4 space, kozepen tab, vegen meg 3 space. Ez a legalja.

Ha nagyon nem megy, ajanlom a pythont, ott esely nincs ra, hogy egyetlen helyen ne indentalj rendesen.

while () 
{
for (;;)
{
if 
{
for (;;) 
{
}
}
else
{
}
}
}

...es akkor a lenyeget meg oda se irtam.

2007. szeptember 25.

dbus

dyuri @ 22:38:39

Ha van ket programunk, es mi azt szeretnenk, hogy az egyik beszelgessen a masikkal, akkor sokfele IPC megoldas kozul valaszthatunk, a hagyomanyosoktol kezdve (szemafor, socket, ...) a modernebbekig (pl. CORBA, RMI, ...) eleg sokmindent valaszthatunk. Utobbiak koze tartozik a DBUS, melyet a modern linux disztribuciok kivetel nelkul tartalmaznak.

Nezzunk egy egyszeru peldat arra, hogy ezt az uzenet-buszt az egyszeru halando hogyan hasznalhatja. Eszkozkent termeszetesen a sokak altal meltan kedvelt python nyelvet valasztottam :P
Ubuntu/debian alatt a python-dbus csomag tartalmazza a szukseges dolgokat.

Nezzuk gyorsan, hogy nez ki egy uj szolgaltatas, utana fuzok hozza egy kis magyarazatot:

import dbus, dbus.service, dbus.glib
import gobject
 
class ButaService(dbus.service.Object):
 
  @dbus.service.method(dbus_interface='hu.horak.ButaInterface',
                       in_signature='s', out_signature='')
  def irjadki(self, szoveg):
    print "Ez jott: %s" % szoveg
 
bus = dbus.SessionBus()
name = dbus.service.BusName('hu.horak.ButaServer', bus=bus)
obj = ButaService(name, '/')
 
loop = gobject.MainLoop()
print 'Figyelek...'
loop.run()

Amint lathato eloszor letrehozzuk a szolgaltatasunkhoz tartozo osztalyt, a dbus.service.Object osztalybol szarmaztatva. Ezen osztaly metodusait exportalhatjuk szolgaltataskent a dbus.service.method dekorator fuggvennyel - ennek a szolgaltatasi felulet nevet kell megadni, illetve a bejovo es kimeno parameterek tipusat - ami pythonban ugye nem egyertelmu, dbuson viszont annak kell lennie.
A szolgaltatasunkat mikor peldanyositjuk, az regisztralja magat egy mar meglevo busznal. Alapertelmezetten ket ilyen busz van, a SessionBus, ami a bejelentkezett felhasznaloknak a sajatja, illetve a SystemBus, ahol a rendszeruzenetek szaladgalnak. Mivel utobbihoz csak rendszergazdai jogokkal tudunk szolgaltatast hozzaadni, ezert az elobbit illik valasztanunk.
Ha kesz a szolgaltatasunk mar csak varni kell, hogy valami kliens hasznalja is azt, ehhez szuksegunk van egy glib kompatibilis mainloopra. Elinditjuk, es varjuk, hogy az elso kliens uzenetet kuldjon nekunk...

...amit meg ennel is joval egyszerubb:

import dbus, dbus.glib
 
bus = dbus.SessionBus()
 
server = dbus.Interface(bus.get_object('hu.horak.ButaServer', '/'),
                        'hu.horak.ButaInterface')
server.irjadki("helloszia")

A kliens egyszeruen annyit csinal, hogy lekeri a beregisztralt szolgaltatasunkat (illetve egy helyi proxy-objektumot keszit, ami vegulis tarsalog a szerver oldallal), majd meghivja az exportalt metodusat. A szerver oldalon pedig megjelenik az "Ez jott: helloszia" uzenet.

Pofonegyszeru. Persze nem arra van kitalalva, hogy masodpercenkent tobbmillio uzenetet kuldozgessunk...
Akit jobban erdekel a tema megnezheti az eredeti tutorialt.

2007. július 19.

Multithreading issues

dyuri @ 9:38:09

Tobbszalas programot fejben debuggolni igen nehez, de nem lehetetlen! :)

2007. június 29.

Django, mint adatbazis eleresi reteg

dyuri @ 11:47:15

Csykinnek fejlesztettem nemreg egy szoftvert (lenyegtelen mit csinal), python alapu, es mysql-t hasznal az adatok tarolasara. Termeszetesen az alkalmazas egyetlen DBHandler nevu osztalyon keresztul kapcsolodik az adatbazishoz, aminek egy leszarmaztatott osztalya a MysqlDBHandler, igy egy sor modositasaval (es egy uj adatbaziskezelo osztaly hozzaadasaval) barmilyen mas adatbazis is hasznalhato lenne. De ebben nincs semmi kulonos, ezt minimum igy illik csinalni.

Viszont a mysql adatbazist ha a valaki az alkalmazason kivulrol szeretne piszkalni, akkor mar nincs olyan jo dolga, vagy parancssorozik, phpmysqladminozik, esetleg ir hozza valami feluletet, amin keresztul nezegetheti. Ellenben eszembe jutott, hogy mi lenne, ha az adatok tarolasara a djangot kernem meg - ezesetben a generalt admin feluleten keresztul egyszeruen elerhetem az adatokat, sot szep webes statisztikakat is eleg egyszeruen tudok utana csinalni. Ugyhogy nekialltam... tovább...

Ez egy blog. A velemenyunk a mienk, ezert szubjektiv, es meglehet, hogy neha csak picit fedi az egyetemes igazsagot. Mellesleg akinek nem tetszik, az nezze helyette a tvt.

Egyebkent nyugodtan lehet idezni, kepeket toltogetni, szabadok vagyunk.

Ha esetleg valami szemelyes kozolnivalod van, amit nem szeretnel kommentbe leirni, akkor tobbek kozott elerhetsz minket a [akiacikketirta] kukac horak pont hu emailcimen.