情况如下:
我正在制作一个小程序来解析服务器日志文件。
我用一个有几千个请求的日志文件测试了它(10000到20000之间并不确切)
我要做的是将日志文本文件加载到内存中,以便我可以查询它们。
这占用了大部分资源。
占用最多cpu时间的方法是那些(最糟糕的罪魁祸首):
string.split - 将行值拆分为值数组
string.contains - 检查用户代理是否包含特定代理字符串。 (确定浏览器ID)
string.tolower - 各种用途
streamreader.readline - 逐行阅读日志文件。
string.startswith - 确定line是列定义行还是带值的行
还有一些我能够替换的。例如字典getter是 也需要很多资源。我没有预料到它是一本字典,应该将其密钥编入索引。我用一个多维数组替换它并节省了一些cpu时间。
现在我在快速双核上运行,加载我提到的文件所需的总时间约为1秒。
现在这真的很糟糕。
想象一下每天有数万次访问的网站。加载日志文件需要几分钟。
那么我的替代方案是什么?如果有的话,因为我认为这只是一个.net限制,我不能做太多。
修改
如果你们中的一些大师想要查看代码并发现问题,请查看我的代码文件:
占用最多资源的功能是到目前为止LogEntry.New 加载所有数据的函数称为Data.Load
创建的LogEntry对象总数:50 000.所用时间:0.9 - 1.0秒。
CPU:amd phenom II x2 545 3ghz。
不是多线程的
答案 0 :(得分:4)
如果没有看到你的代码,就很难知道你是否有任何错误导致你的表现费用。在没有看到一些样本数据的情况下,我们无法合理地尝试实验来了解我们自己的表现。
之前你的词典键是什么?移动到一个多维数组听起来像一个奇怪的举动 - 但我们需要更多的信息来了解你之前对数据做了什么。
请注意,除非您明确并行化工作,否则拥有双核机器不会有任何区别。如果你真的是CPU绑定的那么你可以并行化 - 尽管你需要仔细考虑;你很可能想读一个文本的“块”(几行),并要求一个线程解析它,而不是一次一行。结果代码可能要复杂得多。
我不知道10000行的一秒是否合理,说实话 - 如果您可以发布一些样本数据以及您需要做些什么,我们可以提供更有用的反馈。
编辑:好的,我已经快速查看了代码。一些想法......最重要的是,这可能不是你应该“按需”做的事情。相反,定期解析为后台进程(例如,当日志翻转时)并将有趣的信息放入数据库中 - 然后在需要时查询该数据库。
但是,要优化解析过程:
StreamReader
是否在最后 - 只需致电ReadLine
,直到结果为Nothing
。line.StartsWith("#")
更快 - 我必须测试。 LineFormat
类的实例,该类可以处理任何字段名称,但具体记住您知道的字段索引你会想要的。这也避免了复制每个日志条目的完整字段列表,这非常浪费。可能有其他的事情,但我恐怕现在没有时间进入他们:(
答案 1 :(得分:2)
你看过memory mapped files了吗? (尽管在.NET 4.0中也是如此)
编辑: - 此外,是否可以将这些大文件拆分为较小的文件并解析较小的文件。这是我们在一些大文件中所做的事情,比解析巨型文件更快。
答案 2 :(得分:1)
您可以尝试RegEx。或者更改业务流程,以便更方便地以该速度加载文件。
答案 3 :(得分:0)
您可以尝试延迟加载:例如,一次读取4096字节的文件,查找行结尾并将所有行结尾保存在数组中。现在,如果程序的某些部分需要LogEntry N,请查找该行的起始位置,读取它并动态创建LogEntry对象。 (使用内存映射文件会更容易一些。)尽可能优化,如果调用代码通常需要连续的LogEnties,那么您的代码可以是自动预读下100个日志条目。您可以缓存最后访问的1000个条目。
答案 4 :(得分:0)
您是否考虑过将日志条目加载到数据库并从那里查询?这样,您就可以跳过解析已经存储在数据库中的日志条目。
答案 5 :(得分:0)
你可以做几件事:
Windows服务,每次更改时都会不断解析日志。然后您的UI请求此服务。
或者你可以每分钟或更长时间解析它并缓存结果,你真的需要它实时吗?也许它只需要解析一次?