Ú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