我正在查看Joe Albahari在A Nutshell中的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发布模式下运行的。
意外结果的解释是什么?
答案 0 :(得分:2)
您的代码只生成了一个Regex对象的实例。要使用实际编译的Regex对象,必须指定RegexOptions.Compiled选项。这将通知Regex对象它将以这样的方式使用,即编译自身是值得的前期成本,以便它可以更快地执行。
没有自动完成的原因是,对于有限数量的运行,编译正则表达式的过程实际上将花费比节省的时间更长的时间。 Regex对象用于保存带有元数据的正则表达式,例如Regex引擎选项等,因此可以在编译或不编译的情况下使用。
进行编译的代码是:
var regex = new Regex("/", RegexOptions.Compiled);