【发布时间】:2022-01-25 23:12:57
【问题描述】:
(问题已解决。请参阅下面的答案。)
我刚刚为我的项目(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, %] 自 CPU [unit, %] 模块类别 |||||||||||||||| - [外部调用] System.Collections.Generic.List.InsertRange(int, System.Collections.Generic.IEnumerable) 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 中。不需要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;
}
Code4:注意到 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;
}
Code5:思考 List.AddRange(MatchCollection) 可能听起来很奇怪,我将代码更改为 foreach(...) {List.Add(match)},但什么也没发生,2 分 30 秒。简介说 函数名称 Total CPU [unit, %] 自 CPU [unit, %] 模块类别 |||||||||||||||| - [外部调用] System.Text.RegularExpressions.MatchCollection.MatchCollection+Enumerator.MoveNext() 183804 (92.14%) 183804 (92.14%) 多模块IO |内核
Code6:SelectMany 也需要 2 分 30 秒。这是我最古老的解决方案。
var allMatches = Regexes.SelectMany(i => i.Matches(text));
所以,也许创建一个多达 32676 个项目的列表是件大事,但比创建这些 Match 多 10 倍是超乎想象的。仅在 1 天前完成这项工作需要 27 秒。我今天做了很多更改,并认为分析器会告诉我原因。但它没有。 AddRange() 1 个月前就在那里。我几乎记不起它的名字了。
我会尽量记住白天发生的事情。但是有人可以解释上面的配置文件结果吗?感谢您的帮助。
【问题讨论】:
标签: regex list visual-studio profiler addrange