Mejora de rendimiento
Marcos Sánchez Provencio
rapto en arrakis.es
Vie Sep 19 10:24:31 CEST 2003
Haciendo refrito:
* Es más rápido transformar la lista en otra que se pueda comparar
directamente, sort es mucho más rápida si no redefinimos la función de
comparación.
* No necesitas mktime, vale con empalmar los elementos en orden de
importancia:
YYYY-MM-DD hh:mm:ss
recogiendo cada tramo relevante con operación de corte. Si el mes viene
en letras (grandes ideas del s XX) se puede pasar por un diccionario
antes de montar la cadena comparable. Como hh:mm:ss ya vienen bien, se
sacan en un solo trozo. Va el pseudocódigo
tradMeses={'ene':1, 'feb':2, ...}
lineasEntrada=file (log, 'r').readlines()
#Para sacar los tramos de verdad, a contar con los dedos
lineasCocinadas=[(lin[pos del año]+tradMeses[lin[pos del mes]]+lin[pos
del día]+lin[pos del hhmmss], lin for lin in lineasEntrada ]
#Hacemos un sort nativo, lo que queríamos
lineasCocinadas.sort()
#Nos quedamos con la línea original
lineasOrdenadas=[lin[1] for lin in lineasCocinadas]
Todo esto sin probar, claro, que hablar es gratis :-)
El jue, 18-09-2003 a las 19:08, Tomás Javier Robles Prado escribió:
> Hola,
>
> Estoy escribiendo un programilla que ordene por fecha las líneas de un
> fichero de log de Zope (que es básicamente igual que los de apache).
>
> Las funciones más relevantes del programa son:
>
>
> from sys import argv
> from time import strptime, mktime
>
> DATE_FORMAT = "%d/%b/%Y:%H:%M:%S +0200"
>
> def cmp (l1, l2):
> """Compara dos líneas de log de tipo apache según su fecha"""
> if mktime(strptime(l1.split('[')[1].split(']')[0] , DATE_FORMAT)) >
> mktime(strptime(l2.split('[')[1].split(']')[0] , DATE_FORMAT)) :
> return 1
> elif mktime(strptime(l1.split('[')[1].split(']')[0] ,
> DATE_FORMAT)) == mktime(strptime(l2.split('[')[1].split(']')[0] ,
> DATE_FORMAT)) :
> return 0
> else :
> return -1
>
> def run (log, output):
> try:
> f = file (log, 'r')
> except IOError:
> print "No se ha podido abrir ", log
> return
>
> lineas = []
>
>
> print ("Leyendo de %s..." % log)
> #Se lee el fichero
> l = f.readline()
> while l != "":
>
> #Hay que intentar descartar líneas de este tipo:
> #127.0.0.1 34922 ==> 226 Transfer complete.
> #o este:
> #/usr/lib/zope/z2.py:385: UserWarning: You are running...
> try:
> if l.split()[1][0] == '-':
> #Esto se cumple si es un hit habitual
> lineas.append(l)
>
> except IndexError:
> pass
>
> l = f.readline()
>
> f.close()
>
> print ("Ordenando %d lineas..." % len(lineas))
>
> #Se ordena la lista
> lineas.sort(cmp)
>
> print ("Guardando en %s..." % output)
> try:
> f = file(output, 'w')
> except IOError:
> print "No se ha podido abrir ", output
> return
>
> f.writelines(lineas)
> f.close()
>
> return
>
>
> El tiempo de ejecución con un fichero de unos 40 MB (157431 líneas) es
> desastroso. ¿A alguien se le ocurre alguna optimización útil? Tampoco me
> merece la pena usar psyco ni otros artificios extraños, ya que
> programaré el script para ejecutarse a las 4 d la mañana con prioridades
> bajas. Por cierto, ¿que algoritmo utiliza sort para ordenar?
Más información sobre la lista de distribución Python-es