本来计划使用profile模块进行性能分析作为博客的第二篇记录,然而距上次使用profile也已经距离很长一段时间, 回忆整理起来还是比较麻烦,一个字,太懒了,恩。
之前测代码的运行时间一直使用的是timeit模块,后来才发现还有一个更强大的性能分析工具profile和cprofile,尤其是在你不知道具体哪段代码存在性能问题的时候。
profile很容易入手,在需要测试的代码内加入下面几行,就可以查看到底是哪块代码影响的性能
import cProfile, pstats
pr = cProfile.Profile()
pr.enable()
# ... do something ...
pr.disable()
ps = pstats.Stats(pr).sort_stats('time')//按照时间排序
ps.print_stats()
终于找到罪魁祸首了,大部分时间被strptime和parseMinute这两个函数耗费掉了(如果查看parseMinute代码会发现其也是由strptime实现的)。
def parseMinute(dt, minutesdelta):
""" minutesdelta measured in minutes
"""
try:
dt = dt.strptime(dt, '%Y-%m-%d %H:%M:%S')
seconds = dt.minute * 60 + dt.second
secondsdelta = minutesdelta * 60
delta = math.ceil(seconds/secondsdelta)*secondsdelta - seconds
return datetime(dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second)\
+ timedelta(seconds = delta)
except Exception, ex:
logger.error("%s" % traceback.format_exc())
return None
看来问题就在于stptime上了。Python中datetime,time等类型都有strptime方法,将时间字符串根据格式解析成相应的对象。很多时候我们的需求只是解析”%Y-%m-%d %H:%M:%S”格式的字符串,而strptime会根据locale作相应不同的处理,增加了不必要的复杂度,造成性能瓶颈。当然早有前人发现了这个问题,也给出了解决办法。
【方法1】正则表达式
def parseMinute(dt, minutesdelta):
""" minutesdelta measured in minutes
"""
try:
rep = re.compile(r'(\d{4})-(\d{2})-(\d{2})\s(\d{2}):(\d{2}):(\d{2})')
dt = rep.match(dt)
year, month, day, hour, minute, second = \
int(dt.group(1)), int(dt.group(2)), int(dt.group(3)), int(dt.group(4)), int(dt.group(5)), int(dt.group(6))
seconds = minute * 60 + second
secondsdelta = minutesdelta * 60
delta = math.ceil(seconds/secondsdelta)*secondsdelta - seconds
return datetime(int(year), int(month), int(day), hour, minute, second)\
+ timedelta(seconds = delta)
except Exception, ex:
logger.error("%s" % traceback.format_exc())
return None
【方法2】字符串分隔
def parseMinute(dt, minutesdelta):
""" minutesdelta measured in minutes
"""
try:
date, time = dt.split()
year, month, day = date.split('-')
hour, minute, second = time.split(':')
hour, minute, second = int(hour), int(minute), int(second)
seconds = minute * 60 + second
secondsdelta = minutesdelta * 60
delta = math.ceil(seconds/secondsdelta)*secondsdelta - seconds
return datetime(int(year), int(month), int(day), hour, minute, second)\
+ timedelta(seconds = delta)
except Exception, ex:
logger.error("%s" % traceback.format_exc())
return None
差距还是很容易看的见的。