2010-11-01 5 views
7

J'ai un peu de code d'analyse de journal qui doit transformer un horodatage en un objet datetime. J'utilise datetime.strptime mais cette fonction utilise beaucoup de cputime en fonction de la colonne cumtime de cProfile. Les horodatages sont au format 01/Nov/2010:07:49:33.Python datetime.strptime() Manger beaucoup de temps CPU

La fonction actuelle est:

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

Quelqu'un sait comment je pourrais optimiser cela?

Répondre

13

Si ce sont des formats à largeur fixe, il n'est pas nécessaire d'analyser la ligne - vous pouvez utiliser le découpage en tranches et une recherche par dictionnaire pour obtenir les champs directement.

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 de la manière indiquée par Glenn Maynard montre que cela soit environ 3 fois plus rapide.

+1

Fait cela dans une fonction et testé dans mon code contre le même 1 million de lignes de journal plusieurs fois aller-retour entre cela et strptime(). Le temps d'analyse total est constant quand il passe de 80 à 50 secondes! –

+0

Bonne solution. Pourriez-vous également suggérer ce que je peux faire si j'ai le format de 12 heures pendant des heures. Y at-il un autre moyen de gérer cela en plus de mettre des conditions et de le faire manuellement? – Naman

+1

@Naman vous pouvez ajouter 'am_pm_offset = {'AM': 0, 'PM': 12}' et ajouter cela aux heures. –

2

réponse la plus récente: se déplacer à un strptime() droit n'a pas amélioré le temps de la course, alors je soupçonne qu'il n'y a en réalité aucun problème ici: vous avez simplement écrit un programme, dont l'un des objectifs principaux dans la vie est appeler strptime() très souvent, et vous l'avez écrit assez bien - avec si peu d'autres choses que cela - que les appels strptime() sont tout à fait correctement autorisés à dominer l'exécution. Je pense que vous pourriez considérer cela comme un succès plutôt que comme un échec, à moins que vous ne trouviez que (a) un paramètre Unicode ou LANG fait du travail supplémentaire, ou (b) vous l'appelez plus souvent que nécessaire. Essayez, bien sûr, de ne l'appeler qu'une fois pour chaque date à analyser. :-)

Réponse de suivi après avoir vu la chaîne de date d'exemple: Attendez! Attendez! Pourquoi vous analysez la ligne au lieu d'utiliser une chaîne de mise en forme comme:

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

originale hors la manchette réponse: Si le mois était un entier que vous pourriez faire quelque chose comme ceci:

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

et d'éviter de créer une grosse chaîne juste pour que le strptime() se sépare à nouveau. Je me demande s'il existe un moyen d'accéder directement à la logique du nom du mois pour faire cette conversion textuelle?

+0

Essayé pas la date à part l'analyse syntaxique et de laisser strptime le faire selon votre édition. n'a pas fait beaucoup de différence dans le temps de course ... –

+0

Lors de l'utilisation de strptime(), vous devriez juste nous une chaîne de mise en forme. C'est l'utilisation prévue. –

+0

Eh bien j'ai essayé de mettre cette partie comme son propre ensemble de threads de travail pour l'accélérer. J'ai obtenu les résultats que je parie que la plupart des maîtres non-threading obtiennent quand ils essayent ceci ... deux fois aussi lent ;-) –

2

Qu'est-ce qu'un "beaucoup de temps"? strptime est de prendre environ 30 microsecondes ici:

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) 

impressions 0,000031.

+0

Selon cprofile, le cumul de strptime est de 38 secondes CPU. Le total pour le programme est de 154 secondes CPU. –

+0

Quoi? (et le reste de ce commentaire est ici car StackOverflow traite ses utilisateurs comme des enfants qui ont besoin de longueurs de commentaires forcées) –

+0

Il analyse un fichier journal et strptime prend 38s du total des 154s de temps d'exécution. –

3

Il semble que l'utilisation de strptime() sur une plate-forme Windows utilise une implémentation Python (_strptime.py dans le répertoire Lib). et pas un C. Il pourrait être plus rapide de traiter la chaîne vous-même.

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) 

retours 0,000049 sur mon système, alors 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) 

retours 0,000009

Questions connexes