Conversión rápida de marcas de tiempo para el cálculo de la duración

Tenemos un analizador de registros que analiza los registros en el orden de 100 GB (mi archivo de prueba es de ~ 20 millones de líneas, 1,8 GB). Lleva más tiempo de lo que nos gustaría (más de medio día), así que lo ejecuté contra cProfile y> 75% del tiempo se toma por tiempo de respuesta:

1 0.253 0.253 560.629 560.629 :1() 20000423 202.508 0.000 352.246 0.000 _strptime.py:299(_strptime) 

para calcular las duraciones entre las entradas del registro, actualmente como:

 ltime = datetime.strptime(split_line[time_col].strip(), "%Y-%m-%d %H:%M:%S") lduration = (ltime - otime).total_seconds() 

donde otime es la marca de tiempo de la línea anterior

Los archivos de registro están formateados a lo largo de las líneas de:

 0000 | 774 | 475 | 2017-03-29 00:06:47 | M | 63 0001 | 774 | 475 | 2017-03-29 01:09:03 | M | 63 0000 | 774 | 475 | 2017-03-29 01:19:50 | M | 63 0001 | 774 | 475 | 2017-03-29 09:42:57 | M | 63 0000 | 775 | 475 | 2017-03-29 10:24:34 | M | 63 0001 | 775 | 475 | 2017-03-29 10:33:46 | M | 63 

Se tarda casi 10 minutos en ejecutarse contra el archivo de prueba.

Reemplazando strptime() con esto (de esta pregunta ):

 def to_datetime(d): ltime = datetime.datetime(int(d[:4]), int(d[5:7]), int(d[8:10]), int(d[11:13]), int(d[14:16]), int(d[17:19])) 

Eso reduce a poco más de 3 minutos.

cProfile de nuevo informa:

  1 0.265 0.265 194.538 194.538 :1() 20000423 62.688 0.000 62.688 0.000 analyzer.py:88(to_datetime) 

esta conversión sigue demorando alrededor de un tercio del tiempo para que se ejecute todo el analizador. El revestimiento interno reduce la huella de las conversiones en aproximadamente un 20%, pero seguimos considerando que el 25% del tiempo para procesar estas líneas es convertir la marca de tiempo al formato de datetime y datetime (con total_seconds() consumiendo otro ~ 5% por encima de eso) .

Es posible que termine simplemente escribiendo una marca de tiempo personalizada en segundos para pasar por alto la datetime la datetime , a menos que alguien tenga otra idea shiny.

Así que seguí buscando y encontré un módulo que hace un trabajo fantástico:

Introduciendo ciso8601 :

 from ciso8601 import parse_datetime ... ltime = parse_datetime(sline[time_col].strip()) 

Que, a través de cProfile:

  1 0.254 0.254 123.795 123.795 :1() 20000423 4.188 0.000 4.188 0.000 {ciso8601.parse_datetime} 

que es ~ 84x más rápido que el enfoque ingenuo a través de datetime.strptime() … lo que no es sorprendente, dado que escribieron un módulo en C para hacerlo .