2010-11-01 19 views
7

Ho un codice di analisi del log che deve trasformare un timestamp in un oggetto datetime. Sto usando datetime.strptime ma questa funzione sta usando un sacco di cputime secondo la colonna cumtime di cProfile. I timestamp sono nel formato 01/Nov/2010:07:49:33.Python datetime.strptime() Mangia un sacco di tempo CPU

La funzione corrente è:

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" 
) 

Qualcuno sa come potrei ottimizzare questo?

risposta

13

Se si tratta di formati a larghezza fissa, non è necessario analizzare la linea: è possibile utilizzare il taglio e una ricerca del dizionario per ottenere direttamente i campi.

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) 

test nel modo indicato dal Glenn Maynard mostra che questo è circa 3 volte più veloce.

+1

Inserito questo in una funzione e testato nel mio codice contro lo stesso 1 milione di righe di registro più volte andare avanti e indietro tra questo e strptime(). Tempo totale di analisi costante quando scende da 80 a 50 secondi! –

+0

Buona soluzione. Potrebbe anche suggerire cosa posso fare se ho un formato di 12 ore per ore. C'è un altro modo per gestirlo oltre a mettere le condizioni e farlo manualmente? – Naman

+1

@Naman potresti aggiungere 'am_pm_offset = {'AM': 0, 'PM': 12}' e aggiungerlo alle ore. –

2

più recente risposta: se trasferirsi in una scala strptime() non ha migliorato il tempo di esecuzione, allora il mio sospetto è che non v'è in realtà un problema qui: avete semplicemente scritto un programma, uno dei cui obiettivi principali nella vita è per chiamare lo strptime() molte volte, e lo avete scritto abbastanza bene - con così poche altre cose che fa - che le chiamate strptime() siano abbastanza correttamente autorizzate a dominare il runtime. Penso che potresti considerarlo un successo piuttosto che un fallimento, a meno che non trovi che (a) qualche impostazione Unicode o LANG sta facendo un lavoro extra strptime() o (b) lo chiami più spesso del necessario. Prova, ovviamente, a chiamarlo solo una volta per ogni data da analizzare. :-)

Risposta di follow-up dopo aver visto la stringa di data di esempio: Attendere! Resisti! Perché stai analisi della riga invece di utilizzare una stringa di formattazione come:

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

originale off-the-bracciale-risposta: Se il mese fosse un numero intero si potrebbe fare qualcosa di simile:

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']) 
) 

ed evitare di creare una stringa grande solo per rendere strptime() diviso nuovamente. Mi chiedo se c'è un modo per accedere direttamente alla logica del nome del mese per fare quella conversione testuale?

+0

cercato di non parsing a parte la data e lasciando strptime lo fanno secondo la vostra modifica. non ha fatto molta differenza nel tempo di esecuzione ... –

+0

Quando si utilizza strptime(), si dovrebbe solo noi una stringa di formattazione. Questo è l'uso previsto. –

+0

Beh, ho provato a mettere quella parte come un proprio insieme di thread di lavoro per velocizzarlo. Ho ottenuto i risultati che scommetto la maggior parte dei master non-threading quando tentano questo ... due volte più lentamente ;-) –

2

Che cos'è un "molto tempo"? strptime sta prendendo circa 30 microsecondi qui:

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) 

stampe 0,000031.

+0

In base al profilo cpr, la somma cumulativa per il periodo di tempo è 38 secondi CPU. Il totale per il programma è di 154 secondi CPU. –

+0

Cosa? (e il resto di questo commento è qui perché StackOverflow tratta i suoi utenti come bambini che hanno bisogno di lunghezze di commento obbligatorie minime) –

+0

Sta analizzando un file di log e il tempo di esecuzione è 38 secondi dei 154 totali del tempo di esecuzione. –

3

Sembra che l'utilizzo di strptime() su una piattaforma Windows utilizzi un'implementazione Python (_strptime.py nella directory Lib). e non a C uno. Potrebbe essere più veloce per elaborare la stringa da soli.

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) 

rendimenti 0,000,049 mila sul mio sistema, mentre

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) 

rendimenti 0.000009

Problemi correlati