(问题已解决。请参阅下面的答案。(
我只是为我的项目做了一个简介(winform/C#(,因为我觉得它比以前慢得多。奇怪的是List.AddRange((花费了整个分析过程的92%。
代码1:使用以下代码,完成扫描工作需要2m30s(不在分析模式下(:
var allMatches = new List<Match>();
foreach (var typedRegex in Regexes)
{
var ms = typedRegex.Matches(text); //typedRegex is just Regex.
allMatches.AddRange(ms);
}
函数名称总CPU[单位,%]自身CPU[单位、%]模块类别||||||||||||||||-[外部调用]System.Collections.Generic.List.IInsertRange(int,System.Collections.General.IEnumerable<!0>(146579
代码2:所以我删除了AddRange,它只花了1.6秒:
var allMatches = new List<Match>();
foreach (var typedRegex in Regexes)
{
var ms = typedRegex.Matches(text);
// allMatches.AddRange(ms);
}
代码3:认为可能存在某种";惰性负载";机制,我添加了一个计数器来触发Regex.Maches((。计数器的值显示在UI中。不需要9秒:
public static int Count = 0;
var allMatches = new List<Match>();
foreach (var typedRegex in Regexes)
{
var ms = typedRegex.Matches(text);
// allMatches.AddRange(ms);
Count += ms.Count;
}
代码4:注意到Count的值是32676,所以我为列表预先分配了内存。现在它的成本仍然是9:
public static int Count = 0;
var allMatches = new List<Match>(33000);
foreach (var typedRegex in Regexes)
{
var ms = typedRegex.Matches(text);
// allMatches.AddRange(ms);
Count += ms.Count;
}
代码5:Thinking List.AddRange(MatchCollection(听起来可能很奇怪,我把代码改为foreach(…({List.Add(match(},但什么都没发生,2m30s。个人资料显示函数名称总CPU[单位,%]自身CPU[单位、%]模块类别||||||||||||||||-[外部调用]System.Text.RegularExpressions.MatchCollection.MatchCollection+枚举器.MoveNext((183804
代码6:SelectMany也需要2m30s。这是我最古老的解决方案。
var allMatches = Regexes.SelectMany(i => i.Matches(text));
因此,创建一个多达32676件物品的列表可能是一件大事,但比创建这些Match多10倍是超出想象的。就在一天前完成这项工作花了27秒。我今天做了很多更改,并认为探查器会告诉我原因。但事实并非如此。AddRange((在1个月前就存在了。我以前几乎记不起它的名字了。
我会努力记住白天发生的事情。但有人能解释上面的简介结果吗?谢谢你的帮助。
最后,这不是AddRange((的问题,而是Regex.Matches((。在我优化了正则表达式后,时间成本从2m30s下降到了11s以下。
首先,Regex.Matches((使用某种LazyLoad(和多线程(。这就是为什么它返回MatchCollection而不是普通列表的原因。MatchCollection仅在使用项目时创建该项目。
MatchCollection.Count((的成本低于ToArray((,就像IEnumerable.Count(的成本小于IEnumerable.ToArray((收集的垃圾更少?(。
这是MatchCollection的代码:
private Match GetMatch(int i)
{
if (this._matches.Count > i)
return this._matches[i];
if (this._done)
return (Match) null;
Match match;
do
{
match = this._regex.Run(false, this._prevlen, this._input, 0, this._input.Length, this._startat);
if (!match.Success)
{
this._done = true;
return (Match) null;
}
this._matches.Add(match);
this._prevlen = match.Length;
this._startat = match._textpos;
}
while (this._matches.Count <= i);
return match;
}
而且它太懒了,如果你要求第二项,它对第三项永远不起作用。