【发布时间】:2009-01-09 14:18:43
【问题描述】:
这只是一个满足我好奇心的问题。 但对我来说,这很有趣。
我编写了这个简单的小基准测试。它以随机顺序调用 3 个 Regexp 执行变体几千次:
基本上,我使用相同的模式,但方式不同。
你的普通方式没有任何
RegexOptions。从 .NET 2.0 开始,这些不会被缓存。但应该被“缓存”,因为它被保存在一个相当全局的范围内而不是重置。与
RegexOptions.Compiled通过调用静态
Regex.Match(pattern, input),它确实在 .NET 2.0 中缓存
代码如下:
static List<string> Strings = new List<string>();
static string pattern = ".*_([0-9]+)\\.([^\\.])$";
static Regex Rex = new Regex(pattern);
static Regex RexCompiled = new Regex(pattern, RegexOptions.Compiled);
static Random Rand = new Random(123);
static Stopwatch S1 = new Stopwatch();
static Stopwatch S2 = new Stopwatch();
static Stopwatch S3 = new Stopwatch();
static void Main()
{
int k = 0;
int c = 0;
int c1 = 0;
int c2 = 0;
int c3 = 0;
for (int i = 0; i < 50; i++)
{
Strings.Add("file_" + Rand.Next().ToString() + ".ext");
}
int m = 10000;
for (int j = 0; j < m; j++)
{
c = Rand.Next(1, 4);
if (c == 1)
{
c1++;
k = 0;
S1.Start();
foreach (var item in Strings)
{
var m1 = Rex.Match(item);
if (m1.Success) { k++; };
}
S1.Stop();
}
else if (c == 2)
{
c2++;
k = 0;
S2.Start();
foreach (var item in Strings)
{
var m2 = RexCompiled.Match(item);
if (m2.Success) { k++; };
}
S2.Stop();
}
else if (c == 3)
{
c3++;
k = 0;
S3.Start();
foreach (var item in Strings)
{
var m3 = Regex.Match(item, pattern);
if (m3.Success) { k++; };
}
S3.Stop();
}
}
Console.WriteLine("c: {0}", c1);
Console.WriteLine("Total milliseconds: " + (S1.Elapsed.TotalMilliseconds).ToString());
Console.WriteLine("Adjusted milliseconds: " + (S1.Elapsed.TotalMilliseconds).ToString());
Console.WriteLine("c: {0}", c2);
Console.WriteLine("Total milliseconds: " + (S2.Elapsed.TotalMilliseconds).ToString());
Console.WriteLine("Adjusted milliseconds: " + (S2.Elapsed.TotalMilliseconds*((float)c2/(float)c1)).ToString());
Console.WriteLine("c: {0}", c3);
Console.WriteLine("Total milliseconds: " + (S3.Elapsed.TotalMilliseconds).ToString());
Console.WriteLine("Adjusted milliseconds: " + (S3.Elapsed.TotalMilliseconds*((float)c3/(float)c1)).ToString());
}
每次我调用它时,结果都是这样的:
未编译且未自动缓存: 总毫秒数:6185,2704 调整后的毫秒数:6185,2704 已编译且未自动缓存: 总毫秒数:2562,2519 调整后的毫秒数:2551,56949184038 未编译并自动缓存: 总毫秒数:2378,823 调整后的毫秒数:2336,3187176891所以你有它。不多,但大约有 7-8% 的差异。
这不是唯一的谜。我无法解释为什么第一种方法会慢得多,因为它永远不会重新评估,而是保存在全局静态变量中。
顺便说一句,这是在 .Net 3.5 和 Mono 2.2 上,它们的行为完全相同。在 Windows 上。
那么,有什么想法,为什么编译的变体甚至会落后?
编辑1:
修复代码后,结果现在如下所示:
未编译且未自动缓存: 总毫秒数:6456,5711 调整后的毫秒数:6456,5711 已编译且未自动缓存: 总毫秒数:2668,9028 调整后的毫秒数:2657,77574842168 未编译并自动缓存: 总毫秒数:6637,5472 调整后的毫秒数:6518,94897724836这几乎也淘汰了所有其他问题。
感谢您的回答。
【问题讨论】:
-
我希望看到一个更新的基准测试,它忽略了第一次匹配。这样,我们可以看到正则表达式被 Regex.Match 缓存,并且与编译的时间相对相同。
标签: c# regex performance benchmarking