(问题已解决。请参阅下面的答案。)
我刚刚为我的项目(winform / C#)做了一个配置文件,因为我觉得它的工作速度比以前慢得多。奇怪的是 List.AddRange() 花费了整个分析过程的 92%。
Code1:使用以下代码,完成一次扫描作业需要 2m30s(非 profiling 模式):
var allMatches = new List<Match>();
foreach (var typedRegex in Regexes)
{
var ms = typedRegex.Matches(text); //typedRegex is just Regex.
allMatches.AddRange(ms);
}
函数名称 Total CPU [unit, %] Self CPU [unit, %] 模块类别 |||||||||||||||| - [外部调用] System.Collections.Generic.List.InsertRange(int, System.Collections.Generic.IEnumerable<!0>) 146579 (92.45%) 146579 (92.45%) 多个模块 IO | 核心
Code2:所以我去掉了AddRange,它只需要1.6s:
var allMatches = new List<Match>();
foreach (var typedRegex in Regexes)
{
var ms = typedRegex.Matches(text);
// allMatches.AddRange(ms);
}
Code3:考虑到可能存在某种“延迟加载”机制,我添加了一个计数器来触发 Regex.Maces()。并且计数器的值显示在 UI 中。不需要9s:
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;
}
Code4:注意到 Count 的值为 32676,所以我为列表预先分配了内存。现在它仍然花费 9s:
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;
}
Code5:思考 List.AddRange(MatchCollection) 可能听起来很奇怪,我将代码更改为 foreach(...) {List.Add(match)},但什么也没发生,2 分 30 秒。配置文件显示 Function Name Total CPU [unit, %] Self CPU [unit, %] Module Category ||||||||||||||| - [外部调用] System.Text.RegularExpressions.MatchCollection.MatchCollection+Enumerator.MoveNext() 183804 (92.14%) 183804 (92.14%) 多模块IO | 核心
Code6:SelectMany 也需要 2m30s。这是我最古老的解决方案。
var allMatches = Regexes.SelectMany(i => i.Matches(text));
所以,也许创建一个多达 32676 个项目的列表是一件大事,但比创建这些 Match 多 10 倍是超乎想象的。仅在 1 天前完成这项工作需要 27 秒。我今天做了很多更改,并认为分析器会告诉我原因。但它没有。AddRange() 1 个月前就在那里。我几乎记不起它以前从任何个人资料中的名字。
我会尽量记住白天发生的事情。但是有人可以解释上面的配置文件结果吗?谢谢你的帮助。