解析文件中的文本的代码减慢到停止 c#

Posted

技术标签:

【中文标题】解析文件中的文本的代码减慢到停止 c#【英文标题】:Code to parse text within files slows to a halt c# 【发布时间】:2011-09-20 23:52:20 【问题描述】:
 private static void BuildDictionaryOfRequires(Regex exp, Dictionary<string, string> dictionary, DirectoryInfo dir)
    
        var i = 0;
        var total = dir.EnumerateFiles("*.*", SearchOption.AllDirectories).
                                 Where(x => x.Extension == ".aspx" || x.Extension == ".ascx").Count();
        foreach (var item in dir.EnumerateFiles("*.*", SearchOption.AllDirectories).
                                 Where(x => x.Extension == ".aspx" || x.Extension == ".ascx"))
        
 #if DEBUG
            Stopwatch sw = Stopwatch.StartNew();
 #endif

            var text = File.ReadAllText(item.FullName);

            MatchCollection matches = exp.Matches(text);
            foreach (Match match in matches)
            
                var matchValue = match.Groups[0].Value;

                if (dictionary.ContainsKey(matchValue))
                
                    dictionary[matchValue] = string.Format("0,1", dictionary[matchValue], item.Name);
                
                else
                
                    dictionary.Add(matchValue, item.Name);
                
            

            Console.WriteLine(string.Format("Found matches in 0.", item.Name));

 #if DEBUG
            sw.Stop();
            Console.WriteLine("Time used (float): 0 ms", sw.Elapsed.TotalMilliseconds);
 #endif


            Console.WriteLine(string.Format("0 of 1", (++i).ToString(), total));
        
    

lambda 找到大约 232 个文件。它通过 160 就好了,然后开始爬行。我现在正在分析代码,但想知道是否有什么明显的我做错了。

正则表达式是

    Regex exp = new Regex(@"dojo\.require\([""'][\w\.]+['""]\);?", RegexOptions.IgnoreCase | RegexOptions.Compiled);

所有文件的长度和结构都相似。

大多数文件需要不到 30 毫秒,但有些是 11251 毫秒。

使用更新的正则表达式,整个过程现在需要 1700 毫秒。呸!

【问题讨论】:

Close 和 Dispose 不等价,通常 Dispose 也调用 close,就像 SqlConnection 一样,但这并不意味着它们是等价的,因为 Close 永远不会 Dispose(或至少通常不会)。 @Davide 在注意到性能命中后,我添加了这些是为了好玩。由于 using 语句,我可能可以删除这些行。我将不得不检查 vcsjones 文件,看看我是否能注意到一些东西。 @Davide:来自 MSDN on StreamReader.Close:“这个 Close 实现调用了 Dispose 方法,传递了一个真值。” 请定义“爬行”。是每个文件的处理速度越来越慢,还是文件 160 和文件 1 一样快,但文件 161 永远不会完成? @Michael 文件 0-168 每个在 20 毫秒内完成,然后是 11190 毫秒,然后是 1.5 毫秒,然后是 7 毫秒,然后下一个需要很长时间。所以不,它不是进步的。 【参考方案1】:

尝试简化您的正则表达式:

Regex exp = new Regex(@"dojo\.require\([""'][\w\.]+[""']\)", RegexOptions.IgnoreCase | RegexOptions.Compiled);

更新:如果您想匹配您的示例,则删除末尾的分号。

【讨论】:

实际上它确实匹配。刚刚意识到我并不总是有一个;因为js不需要它所以添加;?解决了这个问题。 @Steve 是的,;? 应该主要靠自己解决你的性能提升。因为只有当带有非可选 ; 的原始正则表达式失败时,才会对性能产生影响。 @JacobEggers 所以 ;?会毁了货吗?有更好的选择吗?【参考方案2】:

我认为当前有问题的部分是这里的正则表达式:

(\w+\.?)*

删除 ?并添加\w*,您将匹配所有相同的字符串,但效率更高。

(\w+\.?)* 可以匹配asdf 很多不同的方式:

asdf asd,f as,d,f a,s,d,f a,sd,f a,s,df a,sdf as,df

我猜你的一些文件有一堆这样的行:

dojo.require('asdf')  //with no ;

您的正则表达式将失败最贪婪的匹配,然后尝试所有其他组合,直到它最终没有得到任何匹配。随着'asdf' 字符串的增长,这可能会变得非常昂贵。

尝试使用:

Regex exp = new Regex(@"dojo\.require\((\""|\')((\w+\.)*\w*)(\""|\')\);");

【讨论】:

我还建议使用RegexOptions.ExplicitCapture,因为没有引用正则表达式中的任何组。 不匹配 dojo.require('dijit.form.Button'); dojo.require('dijit.form'); dojo.require('ijit.widgets.upload.FileUpload') @Michael 加快了速度。尽管如此,仍然会遇到相同的性能颠簸。想知道它是否与文件的编码有关? @MichaelPetito 显式捕获部分,您能否提供对正则表达式的完整更改,以便我查看它与我的测试用例的匹配情况? @Steve:我为您提供了完整的正则表达式作为单独的答案。【参考方案3】:

一些事情:

    取消 DiscardBufferedData 调用。你不需要它,并且 它的价格昂贵。 修复双重处置。请注意,关闭也 调用 Dispose,因此您也可以摆脱它。 其实有一个 File.ReadAllText 方法可以用来摆脱 您正在构建和处置的 StreamReader。

【讨论】:

删除了这些调用,并切换到 File.ReadAllText - 这带来了巨大的性能提升。仍然在一些相对不复杂的文件上放慢速度。它必须与我必须假定的正则表达式有关? 在这一点上,我认为您正在进行的分析将有助于缩小范围。可能是正则表达式,可能是关于该文件的内容,可能是在那个时候进行垃圾收集的终结器线程——很难说。

以上是关于解析文件中的文本的代码减慢到停止 c#的主要内容,如果未能解决你的问题,请参考以下文章

C#解析Json

在 C# 中解析 XML 数据并显示到 ListBox

C# 解析ini类型文件详解

在 C# 中解析带有标题的 CSV 文件

统一读取和解析 C# 中的 Json 文件

使用 C 使用多线程从文本文件中解析单词