如何在Python中创建timedelta列表?
我在这个网站上搜索了很久,看到很多关于时间差的讨论,但还没找到我想要的东西。
简单来说,我有一份消息列表,这些消息是由一个通信服务器接收到的。我想计算每条消息发送和接收之间的延迟时间。它的格式是这样的:
161336.934072 - TMsg out: [O] enter order. RefID [123] OrdID [4568]
161336.934159 - TMsg in: [A] accepted. ordID [456] RefNumber [123]
这些消息中夹杂着其他消息,但我只想计算那些具有相同RefID的发送消息和接收消息之间的时间差。
到目前为止,为了从主日志中筛选出哪些是T消息,我一直在这样做,但效率真的很低。我不想每次都创建新文件:
big_file = open('C:/Users/kdalton/Documents/Minicomm.txt', 'r')
small_file1 = open('small_file1.txt', 'w')
for line in big_file:
if 'T' in line: small_file1.write(line)
big_file.close()
small_file1.close()
我该如何计算这两条消息之间的时间差,并从主日志中筛选出这些消息呢?
2 个回答
首先,不要直接写出原始的日志行。其次,使用字典。
tdeltas = {} # this is an empty dict
if "T" in line:
get Refid number
if Refid in tedeltas:
tdeltas[Refid] = timestamp - tdeltas[Refid]
else:
tdeltas[Refid] = timestamp
然后在最后,把它转换成列表并打印出来。
allRefids = sorted(tdeltas.keys())
for k in allRefids:
print k+": "+tdeltas[k]+" secs"
你可能想把日期转换成来自datetime
模块的time
对象,然后使用时间差对象存储在字典里。虽然这次任务可能不太值得这样做,但学习如何使用datetime模块是很有用的。
另外,我没有详细讲解如何从输入字符串中解析出Refid,以及将时间从字符串转换为浮点数再转换回来的可能问题。
实际上,仅仅存储时间差会造成混淆,如果你遇到一个不被接受的Refid。如果我真的在做这个,我会在值里存储一个元组,包含开始时间、结束时间和时间差。对于一个新记录,它看起来会像这样:(161336.934072,0,0)
,而在检测到接受后,它会变成这样:(161336.934072,161336.934159,.000087)
。如果日志记录活动是持续的,比如一个24小时不间断的全球电商网站,那么我会定期检查字典,找出任何时间差不为零的条目,报告它们并删除。然后我会把剩下的值按开始时间排序,报告并删除那些开始时间太旧的记录,因为这意味着这些交易已经失败,永远不会完成。
此外,在一个真实的电商网站中,我可能会考虑使用像Redis或Memcache这样的外部字典,这样报告和维护可以由其他服务器或应用程序来完成。
这个生成器函数会返回一个元组,里面包含了消息的ID和发送时间的差值。(如果你想对时间差做更复杂的处理,可以看看 datetime.timedelta
)。需要注意的是,这里假设发送的消息总是在接收的消息之前出现。
def get_time_deltas(infile):
entries = (line.split() for line in open(INFILE, "r"))
ts = {}
for e in entries:
if len(e) == 11 and " ".join(e[2:5]) == "TMsg out: [O]":
ts[e[8]] = e[0] # store timestamp for id
elif len(e) == 10 and " ".join(e[2:5]) == "TMsg in: [A]":
in_ts, ref_id = e[0], e[9]
# Raises KeyError if out msg not seen yet. Handle if required.
out_ts = ts.pop(ref_id) # get ts for this id
yield (ref_id[1:-1], float(in_ts) - float(out_ts))
现在你可以从中获取一个列表:
>>> INFILE = 'C:/Users/kdalton/Documents/Minicomm.txt'
>>> list(get_time_deltas(INFILE))
[('123', 8.699999307282269e-05), ('1233', 0.00028700000257231295)]
或者把它写入一个文件:
>>> with open("out.txt", "w") as outfile:
... for id, td in get_time_deltas(INFILE):
... outfile.write("Msg %s took %f seconds\n", (id, td))
或者把它串联到一个更复杂的工作流程中。
更新:
(这是根据实际数据的观察做出的回应)
试试这个:
def get_time_deltas(infile):
entries = (line.split() for line in open(INFILE, "r"))
ts = {}
for e in entries:
if " ".join(e[2:5]) == "OuchMsg out: [O]":
ts[e[8]] = e[0] # store timestamp for id
elif " ".join(e[2:5]) == "OuchMsg in: [A]":
in_ts, ref_id = e[0], e[7]
out_ts = ts.pop(ref_id, None) # get ts for this id
# TODO: handle case where out_ts = None (no id found)
yield (ref_id[1:-1], float(in_ts) - float(out_ts))
INFILE = 'C:/Users/kdalton/Documents/Minicomm.txt'
print list(get_time_deltas(INFILE))
这个版本的变化:
- 字段的数量和问题中提供的示例输入不一致。移除了基于条目数量的检查
in
消息的ordID
是和out
消息中的refID
匹配的- 使用了
OuchMsg
而不是TMsg
更新 2
要计算时间差的平均值:
deltas = [d for _, d in get_time_deltas(INFILE)]
average = sum(deltas) / len(deltas)
或者,如果你之前生成过一个包含所有数据的列表,我们可以重用它,而不是重新解析文件:
data = list(get_time_deltas(INFILE))
# .. use data for something some operation ...
# calculate average using the list
average = sum(d for _, d in data) / len(data)