2010-11-01 27 views
7

Tengo un código de análisis de registro que necesita convertir una marca de tiempo en un objeto de fecha y hora. Estoy usando datetime.strptime pero esta función usa mucho cputime de acuerdo con la columna cumtime de cProfile. Las marcas de tiempo están en el formato de 01/Nov/2010:07:49:33.Python datetime.strptime() Comer mucho tiempo de CPU

La función actual es:

new_entry['time'] = datetime.strptime(
     parsed_line['day'] + 
     parsed_line['month'] + 
     parsed_line['year'] + 
     parsed_line['hour'] + 
     parsed_line['minute'] + 
     parsed_line['second'] 
     , "%d%b%Y%H%M%S" 
) 

Alguien sabe cómo podría optimizar este?

Respuesta

13

Si se trata de formatos de ancho fijo, entonces no hay necesidad de analizar la línea; puede usar el corte y una búsqueda del diccionario para obtener los campos directamente.

month_abbreviations = {'Jan': 1, 'Feb': 2, 'Mar': 3, 'Apr': 4, 
         'May': 5, 'Jun': 6, 'Jul': 7, 'Aug': 8, 
         'Sep': 9, 'Oct': 10, 'Nov': 11, 'Dec': 12} 
year = int(line[7:11]) 
month = month_abbreviations[line[3:6]] 
day = int(line[0:2]) 
hour = int(line[12:14]) 
minute = int(line[15:17]) 
second = int(line[18:20]) 
new_entry['time'] = datetime.datetime(year, month, day, hour, minute, second) 

Testing de la manera mostrada por Glenn Maynard muestra que esto es aproximadamente 3 veces más rápido.

+1

Lo hice en una función y lo probé en mi código contra el mismo millón de líneas de registro varias veces yendo y viniendo entre esto y strptime(). ¡Tiempo total de Parse consistentemente cuando bajó de 80 a 50 segundos! –

+0

Buena solución. ¿Podría sugerir también qué puedo hacer si tengo un formato de 12 horas por horas? ¿Hay alguna otra forma de manejar eso además de poner condiciones y hacerlo manualmente? – Naman

+1

@Naman podría agregar 'am_pm_offset = {'AM': 0, 'PM': 12}' y agregar eso a las horas. –

2

respuesta más reciente: si se está moviendo a una recta strptime() no ha mejorado el tiempo de ejecución, entonces mi sospecha es que en realidad no hay problema aquí: simplemente han escrito un programa, uno de cuyos principales objetivos en la vida es para llamar al strptime() muchas veces, y lo ha escrito lo suficientemente bien - con tan poco otras cosas que lo hace - que las llamadas strptime() se les permite dominar de manera bastante adecuada el tiempo de ejecución. Creo que podría contar esto como un éxito en lugar de como un fracaso, a menos que encuentre que (a) cierta configuración de Unicode o LANG hace que strptime() trabaje más, o (b) la llame más a menudo de lo necesario. Intente, por supuesto, llamarlo solo una vez para cada fecha para analizar. :-)

Respuesta de seguimiento después de ver la cadena de fecha de ejemplo: ¡Espere! ¡Espere! ¿Por qué estás analizar la línea en lugar de usar una cadena de formato, como:

"%d/%b/%Y:%H:%M:%S" 

original fuera de la manga respuestas: Si el mes fuera un número entero que podría hacer algo como esto:

new_entry['time'] = datetime.datetime(
    int(parsed_line['year']), 
    int(parsed_line['month']), 
    int(parsed_line['day']), 
    int(parsed_line['hour']), 
    int(parsed_line['minute']), 
    int(parsed_line['second']) 
) 

y evite crear una cadena grande solo para que strptime() vuelva a separarla. Me pregunto si hay una forma de acceder directamente a la lógica del nombre del mes para hacer esa conversión textual.

+0

trató de no analizar, aparte de la fecha y dejar strptime lo hacen según su edición. no hizo mucha diferencia en el tiempo de ejecución ... –

+0

Al usar strptime(), debería usar una cadena de formato. Ese es el uso previsto. –

+0

Bueno, traté de poner esa parte como su propio conjunto de hilos de trabajo para acelerarlo. Obtuve los resultados que apuesto a que la mayoría de los maestros sin threading obtienen cuando intentan esto ... el doble de lento ;-) –

2

¿Qué es "mucho tiempo"? strptime se está llevando a unos 30 microsegundos aquí:

from datetime import datetime 
import timeit 
def f(): 
    datetime.strptime("01/Nov/2010:07:49:33", "%d/%b/%Y:%H:%M:%S") 
n = 100000 
print "%.6f" % (timeit.timeit(f, number=n)/n) 

impresiones 0.000031.

+0

Según cprofile, el acumulado para strptime es de 38 CPU segundos. El total para el programa es de 154 CPU segundos. –

+0

¿Qué? (y el resto de este comentario está aquí porque StackOverflow trata a sus usuarios como niños que necesitan longitudes de comentario mínimas forzadas) –

+0

Está analizando un archivo de registro y strptime está tomando 38s del total de 154s del tiempo de ejecución. –

3

Parece que usar strptime() en una plataforma de Windows usa una implementación de Python (_strptime.py en el directorio de Lib). y no una C Puede ser más rápido procesar la cadena usted mismo.

from datetime import datetime 
import timeit 

def f(): 
    datetime.strptime ("2010-11-01", "%Y-%m-%d") 

n = 100000 
print "%.6f" % (timeit.timeit(f, number=n)/n) 

vuelve 0.000049 en mi sistema, mientras que

from datetime import date 
import timeit 

def f(): 
    parts = [int (x) for x in "2010-11-01".split ("-")] 
    return date (parts[0], parts[1], parts[2])  

n = 100000 
print "%.6f" % (timeit.timeit(f, number=n)/n) 

vuelve 0,000009

Cuestiones relacionadas