|
|
Últimos Cambios |
Blog personal: El hilo del laberinto
|
|
|
Última Actualización: 21 de Enero de 2003 - Martes
En Python, al igual que ocurre con Java, cuando se manipulan cadenas se crean y se destruyen objetos constantemente. Ello supone un mayor uso de memoria y, sobre todo, una baja eficiencia.
Pero haciendo un uso inteligente de las características del lenguaje, es posible optimizar estas operaciones de forma considerable.
Los siguientes ejemplos utilizan Python 2.2.2, sobre una máquina UltraSparc I:
Se busca y elimina los textos que aparezcan entre < >.
from time import time
def eliminaTags1(texto) :
t=time()
a=0
while a>=0 :
a=texto.find("<")
if a>=0 :
b=texto.find(">",a)
texto=texto[:a]+texto[b+1:]
print time()-t
return texto
En esta opción, sencilla, eliminar cada tag supone crear tres cadenas nuevas, y eliminar una cadena antigua y dos nuevas.
from time import time
def eliminaTags2(texto) :
t=time()
a=b=0
while a>=0 :
a=texto.find("<",b)
if a>=0 :
b=texto.find(">",a)
texto=texto[:a]+texto[b+1:]
b-=b-a
print time()-t
return texto
Esta opción es similar a la anterior, pero no empieza a buscar desde el principio, sino donde lo había dejado.
from time import time
def eliminaTags3(texto) :
t=time()
s=""
a=b=0
while a>=0 :
a=texto.find("<",b)
if a>=0 :
s+=texto[b:a]
b=texto.find(">",a)+1
if b : s+=texto[b:]
if s: texto=s
print time()-t
return texto
Esta opción crea dos cadenas nuevas y elimina una antigua y una nueva. Según la implementación, el "s+=" podría incluso reutilizar el viejo objeto, lo que supondría reducir aún más los objetos creados y destruídos.
Las cadenas generadas son más cortas que en el ejemplo anterior. La ocupación de memoria es, aproximadamente, el doble, porque mantenemos la cadena original hasta terminar de procesarla.
Además, la búsqueda en la cadena original es incremental y no se empieza desde el principio en cada pasada. La importancia de este hecho crece a medida que lo hace la longitud de la cadena y el número de tags presentes en ella.
from time import time
from string import join,find
def eliminaTags4(texto) :
t=time()
s=[]
a=b=0
while a>=0 :
#a=find(texto,"<",b) # Esta operación es lenta
a=texto.find("<",b)
if a>=0 :
s.append(texto[b:a])
#b=find(texto,">",a)+1 # Esta operación es lenta
b=texto.find(">",a)+1
if b : s.append(texto[b:])
if s: texto=join(s,"") # Esta operación es muy rápida
print time()-t
return texto
Esta rutina es más rápida. Resulta extraño que el "find" del módulo "string" sea más lento que el nativo.
from time import time
from cStringIO import StringIO
def eliminaTags5(texto) :
t=time()
s=StringIO()
a=b=0
while a>=0 :
a=texto.find("<",b)
if a>=0 :
s.write(texto[b:a])
b=texto.find(">",a)+1
if b : s.write(texto[b:])
if s.tell(): texto=s.getvalue()
print time()-t
return texto
| Opción 1 | Opción 2 | Opción 3 | Opción 4 | Opción 5 | |
|---|---|---|---|---|---|
| 4925 bytes | 100% | -- | 325% | -- | -- |
| 12058 bytes | 27% | 49% | 145% | 167% | 165% |
| 23906 bytes | 8% | 20% | 63% | 91% | 86% |
| 59049 bytes | 1% | 2% | 17% | 36% | 36% |
Se observa claramente que la tercera opción es mucho más rápida, y que escala bastante mejor con el tamaño de la cadena. De hecho la primera opción tiene un comportamiento cuadrático, mientras que la tercera es aproximadamente lineal.
La cuarta opción es la más rápida para cadenas largas, y su ventaja respecto a la 3 crece a medida que lo hace la cadena. Para cadenas cortas, las opciones 3 y 4 están prácticamente empatadas, destacándose ligeramente la opción 3.
Más información sobre los OpenBadges
Donación BitCoin: 19niBN42ac2pqDQFx6GJZxry2JQSFvwAfS
