Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.net net中的高性能文本文件解析_.net_Performance_Optimization_String - Fatal编程技术网

.net net中的高性能文本文件解析

.net net中的高性能文本文件解析,.net,performance,optimization,string,.net,Performance,Optimization,String,情况如下: 我正在做一个小程序来解析服务器日志文件 我用一个包含数千个请求的日志文件对它进行了测试(10000到20000个请求之间,不知道确切的数字) 我要做的是将日志文本文件加载到内存中,以便查询它们 这占用了最多的资源 占用cpu时间最多的方法如下(罪魁祸首在前): string.split-将行值拆分为一个值数组 string.contains-检查用户代理是否包含特定的代理字符串。(确定浏览器ID) string.tolower多种用途 streamreader.readline-逐行

情况如下:

我正在做一个小程序来解析服务器日志文件

我用一个包含数千个请求的日志文件对它进行了测试(10000到20000个请求之间,不知道确切的数字)

我要做的是将日志文本文件加载到内存中,以便查询它们

这占用了最多的资源

占用cpu时间最多的方法如下(罪魁祸首在前):

string.split-将行值拆分为一个值数组

string.contains-检查用户代理是否包含特定的代理字符串。(确定浏览器ID)

string.tolower多种用途

streamreader.readline-逐行读取日志文件

string.startswith-确定行是列定义行还是带值的行

还有一些是我可以替代的。例如,dictionary getter是 也需要很多资源。这是我没想到的,因为它是一本字典,应该有索引键。我用多维数组替换了它,节省了一些cpu时间

现在我运行在一个快速双核上,加载我提到的文件所需的总时间约为1秒

现在这真的很糟糕

想象一下,一个网站每天有成千上万的访问量。加载日志文件需要几分钟的时间

那么我的选择是什么呢?如果有的话,因为我认为这只是一个.net限制,对此我无能为力

编辑:

如果您中的一些大师想查看代码并发现问题,请参阅我的代码文件:

占用资源最多的函数是LogEntry.New 加载所有数据的函数称为data.Load

创建的LogEntry对象总数:50000。所用时间:0.9-1.0秒

CPU:amd phenom II x2 545 3ghz


不是多线程的

您可以尝试RegEx。或者更改业务流程,以便更方便地以该速度加载文件。

您已经看过了吗?(不过这是在.NET4.0中)


编辑:-此外,还可以将这些大文件拆分为较小的文件并解析较小的文件。这是我们在一些大文件中所做的事情,比解析大文件要快。

如果看不到您的代码,很难知道您是否有任何错误会影响性能。如果看不到一些样本数据,我们就无法合理地尝试实验来了解我们自己的情况

你以前的字典钥匙是什么?移动到多维数组听起来很奇怪,但我们需要更多的信息来了解您之前对数据做了什么

请注意,除非您明确地将工作并行化,否则使用双核机器不会有任何区别。如果你真的受到CPU的限制,那么你可以并行化——尽管你需要小心地这样做;您很可能希望阅读一段文本(几行),并要求一个线程对其进行解析,而不是一次只发送一行。不过,生成的代码可能要复杂得多

老实说,我不知道10000行一秒钟是否合理——如果你能发布一些样本数据以及你需要如何处理这些数据,我们可以提供更多有用的反馈

编辑:好的,我已经快速查看了代码。一些想法

最重要的是,这可能不是你应该“按需”做的事情。相反,作为后台进程定期解析(例如,当日志滚动时),并将感兴趣的信息放入数据库中,然后在需要时查询该数据库

但是,要优化解析过程,请执行以下操作:

  • 我个人不会一直检查
    StreamReader
    是否在末尾-只需调用
    ReadLine
    ,直到结果为
    Nothing
  • 如果您希望“#fields”行首先出现,那么请在循环之外阅读它。然后,您不需要查看是否已经在每次迭代中获得了字段
  • 如果您知道一行是非空的,那么测试第一个字符为“#”可能比调用
    line.StartsWith(“#”)要快得多,我必须进行测试
  • 每次您询问日期、时间、URI系统或用户代理时,都会扫描字段;相反,当您解析“#fields”行时,您可以创建一个新的
    LineFormat
    类的实例,该类可以处理任何字段名,但具体记住您知道需要的字段索引。这也避免了为每个日志条目复制完整的字段列表,这是非常浪费的
  • 拆分字符串时,您会得到比正常情况更多的信息:您知道需要多少字段,并且您知道您只拆分一个字符。您可能会编写一个优化版本
  • 单独解析日期和时间字段,然后合并结果,而不是将它们串联起来,然后进行解析,可能会更快。我得测试一下
  • 多维数组的速度明显慢于一维数组。如果您确实希望保持“每个条目复制所有字段名”的想法,那么将其分为两个数组是值得的:一个用于字段,一个用于值

可能还有其他事情,但我恐怕现在没有时间讨论:(

您可以尝试延迟加载:例如,一次读取4096字节的文件,查找行尾并将所有行尾保存在一个数组中。现在,如果程序的某些部分需要日志项N,请查找该行的起始位置,读取该行并动态创建一个日志项对象。(使用内存映射文件会更容易一些。)尽可能优化,如果调用代码通常需要