解析文件中的文本的代码减慢到停止 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
很多不同的方式:
我猜你的一些文件有一堆这样的行:
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#的主要内容,如果未能解决你的问题,请参考以下文章