[python] Podivné chování

Jirka Vejrazka jirka.vejrazka na gmail.com
Středa Srpen 26 11:46:35 CEST 2009


No, ten skript ma nekolik zajimavosti, zkusim popsat co mne napada:

1) obecne se nedoporucuje pouzivat += na stringy (popisu dale) - to je
pravdepodobne hlavni pricina pomalosti
2) buffer je zbytecne maly, klidne se da pouzit treba 64K nebo tak
nejak (to nebude mit zasadni vliv na rychlost, ale nejaka procenta to
taky udela
3) zbytecne zavorky:
  - "while (1)" se obvykle pise "while 1" nebo moderneji "while True"
  - "if (buffer == ""):" taky nepotrebuje zavorky, obvykle se tohle
pise jako "if not buffer:" protoze prazdny string je vyhodnocen jako
False

No a ted k tomu problemu. Nejsem si 100% jisty, ale rekl bych ze
problemem je v to, ze v Pythonu jsou stringy "immutable", tj. nedaji
se menit na jednom miste v pameti. V cyklu se provadi "data +=
buffer". To byval ukazkovy priklad toho, jak v Pythonu se stringy
nepracovat, protoze az nekdy do Pythonu 2.3 byla takhle operace velmi
pomala. Znamenala totiz:
  - najdi data v pameti
  - najdi misto v pameti, kam se vejdou "data + buffer"
  - prekopiruj data na nove misto
  - prilep na konec buffer
  - predelej vsechny odkazy na data, aby ukazovaly na nove misto v pameti
  - uvolni ten kus pameti, kde driv byla data

Python 2.4 tuhle operaci rychlostne optimalizoval, takze uz nebyla
nebetycne pomala. Ja bych si tipnul, ze ten "normalni prubeh" tveho
skriptu je normalne rychly prave kvuli te optimalizaci. V okamziku,
kdy se na objekt "data" vyrobi dalsi reference ("global data"), tak z
nejakeho duvodu Python tu optimalizaci nepouzije a vrati se ke
staremu, pomalemu chovani. Coz znamena, ze na kazdy 1 precteny
kilobajt zkopiruje cela "data" v pameti na jine misto. Pro 100MB
nactenych dat je to "hodnekrat" :)

Pro zrychleni bych doporucil:

tmp = []
while True:
    buffer = sys.stdin.read(1024)  # nebo radeji 65536
    if not buffer:
        break
    tmp.append(buffer)
data = ''.join(tmp)

Snad to pomuze, nezkousel jsem to.

    Jirka

> Zdravím, vytvoříme si libovolný soubor cca 100MB a ten pak předáme na stdin
> následujícímu skriptu:
>
>    import sys
>
>    data = ""
>    while (1):
>        buffer = sys.stdin.read(1024)
>
>        if (buffer == ""):
>            break
>
>        data += buffer

>


Další informace o konferenci Python