我正在阅读Joe Albahari的《C# 5.0权威指南》第26章有关正则表达式的内容,他说:
在一些之前的示例中,我们重复使用静态
RegEx
方法来处理相同的模式。在这种情况下,另一种方法是使用该模式实例化一个Regex
对象,然后调用实例方法...
// Code example from the book
Regex r = new Regex (@"sausages?");
Console.WriteLine (r.Match ("sausage")); // sausage
Console.WriteLine (r.Match ("sausages")); // sausages
这不仅是一种语法上的方便:在内部……这会导致比较快(最高可达10倍)的匹配,代价是需要付出小小的初始编译成本(几十微秒)。
于是我就好奇地写了一个基准测试。这个程序分割字符串,迭代调用约3200万次Regex
的静态调用和实例调用,以及一种执行相同任务的另一种方式。
class Program {
static void Main(string[] args) {
var str = "01/02/03/04/05/06/07/08/09/10";
var regex = new Regex("/");
var results = new List<Tuple<string, long>>();
for (int j = 0; j < 128; j++) {
var s = Stopwatch.StartNew();
for (var i = 0; i < 1024 * 1024; i++) {
RegexSplit(str);
}
s.Stop();
results.Add(new Tuple<string, long>("Regex", s.ElapsedTicks));
s = Stopwatch.StartNew();
for (var i = 0; i < 1024 * 1024; i++) {
CompiledRegexSplit(str, regex);
}
s.Stop();
results.Add(new Tuple<string, long>("Compiled", s.ElapsedTicks));
s = Stopwatch.StartNew();
for (var i = 0; i < 1024 * 1024; i++) {
StringSplit(str);
}
s.Stop();
results.Add(new Tuple<string, long>("String", s.ElapsedTicks));
Console.Write(".");
}
var resultsGroup = from it in results
group it by it.Item1
into g
select new {
Type = g.Key,
Avg = g.Average(git => git.Item2)
};
resultsGroup.ToList().ForEach(it => Console.WriteLine("{0}: {1:000000000.00}", it.Type, it.Avg));
}
static void StringSplit(string str) {
var split = str.Split('/');
}
static void CompiledRegexSplit(string str, Regex regex) {
var split = regex.Split(str);
}
static void RegexSplit(string str) {
var split = Regex.Split(str, "/");
}
}
并获得了以下结果:
Regex: 12257601.40
Compiled: 10869996.92
String: 01328636.27
根据这本书,我并没有预料到这个结果,而且我怀疑一个Regex
实例化需要花费1200万个时钟周期。
这个运行是在.NET 4.5,x64发行模式下进行的。
那么这个意外结果的解释是什么?
RegexOptions.Compiled
。代码中创建了一个正则表达式对象,使用了该选项:Regex regex = new Regex(pattern, RegexOptions.Compiled);。 - Bidouvar regex = new Regex("/");
- leppieRegex r = new Regex(@"sausages?")
- 更新问题 - jdphenix