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