.net net中的高性能文本文件解析
情况如下: 我正在做一个小程序来解析服务器日志文件 我用一个包含数千个请求的日志文件对它进行了测试(10000到20000个请求之间,不知道确切的数字) 我要做的是将日志文本文件加载到内存中,以便查询它们 这占用了最多的资源 占用cpu时间最多的方法如下(罪魁祸首在前): string.split-将行值拆分为一个值数组 string.contains-检查用户代理是否包含特定的代理字符串。(确定浏览器ID) string.tolower多种用途 streamreader.readline-逐行读取日志文件 string.startswith-确定行是列定义行还是带值的行 还有一些是我可以替代的。例如,dictionary getter是 也需要很多资源。这是我没想到的,因为它是一本字典,应该有索引键。我用多维数组替换了它,节省了一些cpu时间 现在我运行在一个快速双核上,加载我提到的文件所需的总时间约为1秒 现在这真的很糟糕 想象一下,一个网站每天有成千上万的访问量。加载日志文件需要几分钟的时间 那么我的选择是什么呢?如果有的话,因为我认为这只是一个.net限制,对此我无能为力 编辑: 如果您中的一些大师想查看代码并发现问题,请参阅我的代码文件:.net net中的高性能文本文件解析,.net,performance,optimization,string,.net,Performance,Optimization,String,情况如下: 我正在做一个小程序来解析服务器日志文件 我用一个包含数千个请求的日志文件对它进行了测试(10000到20000个请求之间,不知道确切的数字) 我要做的是将日志文本文件加载到内存中,以便查询它们 这占用了最多的资源 占用cpu时间最多的方法如下(罪魁祸首在前): string.split-将行值拆分为一个值数组 string.contains-检查用户代理是否包含特定的代理字符串。(确定浏览器ID) string.tolower多种用途 streamreader.readline-逐行
不是多线程的您可以尝试RegEx。或者更改业务流程,以便更方便地以该速度加载文件。您已经看过了吗?(不过这是在.NET4.0中)
编辑:-此外,还可以将这些大文件拆分为较小的文件并解析较小的文件。这是我们在一些大文件中所做的事情,比解析大文件要快。如果看不到您的代码,很难知道您是否有任何错误会影响性能。如果看不到一些样本数据,我们就无法合理地尝试实验来了解我们自己的情况 你以前的字典钥匙是什么?移动到多维数组听起来很奇怪,但我们需要更多的信息来了解您之前对数据做了什么 请注意,除非您明确地将工作并行化,否则使用双核机器不会有任何区别。如果你真的受到CPU的限制,那么你可以并行化——尽管你需要小心地这样做;您很可能希望阅读一段文本(几行),并要求一个线程对其进行解析,而不是一次只发送一行。不过,生成的代码可能要复杂得多 老实说,我不知道10000行一秒钟是否合理——如果你能发布一些样本数据以及你需要如何处理这些数据,我们可以提供更多有用的反馈 编辑:好的,我已经快速查看了代码。一些想法 最重要的是,这可能不是你应该“按需”做的事情。相反,作为后台进程定期解析(例如,当日志滚动时),并将感兴趣的信息放入数据库中,然后在需要时查询该数据库 但是,要优化解析过程,请执行以下操作:
- 我个人不会一直检查
是否在末尾-只需调用StreamReader
,直到结果为ReadLine
Nothing
- 如果您希望“#fields”行首先出现,那么请在循环之外阅读它。然后,您不需要查看是否已经在每次迭代中获得了字段
- 如果您知道一行是非空的,那么测试第一个字符为“#”可能比调用
line.StartsWith(“#”)要快得多,我必须进行测试
- 每次您询问日期、时间、URI系统或用户代理时,都会扫描字段;相反,当您解析“#fields”行时,您可以创建一个新的
类的实例,该类可以处理任何字段名,但具体记住您知道需要的字段索引。这也避免了为每个日志条目复制完整的字段列表,这是非常浪费的LineFormat
- 拆分字符串时,您会得到比正常情况更多的信息:您知道需要多少字段,并且您知道您只拆分一个字符。您可能会编写一个优化版本
- 单独解析日期和时间字段,然后合并结果,而不是将它们串联起来,然后进行解析,可能会更快。我得测试一下
- 多维数组的速度明显慢于一维数组。如果您确实希望保持“每个条目复制所有字段名”的想法,那么将其分为两个数组是值得的:一个用于字段,一个用于值
可能还有其他事情,但我恐怕现在没有时间讨论:(您可以尝试延迟加载:例如,一次读取4096字节的文件,查找行尾并将所有行尾保存在一个数组中。现在,如果程序的某些部分需要日志项N,请查找该行的起始位置,读取该行并动态创建一个日志项对象。(使用内存映射文件会更容易一些。)尽可能优化,如果调用代码通常需要