我的基准测试与您的基准测试不一致。
我运行了与 Alex 相同的基准测试,得到了相反的结果。然后我稍微调整了基准,并再次观察到Cast
比OfType
.
它没有太多内容,但我相信它Cast
确实有优势,因为它的迭代器更简单。(不is
检查。)
编辑:实际上经过一些进一步的调整,我设法Cast
比OfType
.
以下是迄今为止我发现的最大差异的基准代码:
Stopwatch sw1 = new Stopwatch();
Stopwatch sw2 = new Stopwatch();
var ma = Enumerable.Range(1, 100000).Select(i => i.ToString()).ToArray();
var x = ma.OfType<string>().ToArray();
var y = ma.Cast<string>().ToArray();
for (int i = 0; i < 1000; i++)
{
if (i%2 == 0)
{
sw1.Start();
var arr = ma.OfType<string>().ToArray();
sw1.Stop();
sw2.Start();
var arr2 = ma.Cast<string>().ToArray();
sw2.Stop();
}
else
{
sw2.Start();
var arr2 = ma.Cast<string>().ToArray();
sw2.Stop();
sw1.Start();
var arr = ma.OfType<string>().ToArray();
sw1.Stop();
}
}
Console.WriteLine("OfType: " + sw1.ElapsedMilliseconds.ToString());
Console.WriteLine("Cast: " + sw2.ElapsedMilliseconds.ToString());
Console.ReadLine();
我所做的调整:
- 在开始时执行一次“生成字符串列表”工作,然后“结晶”它。
- 在开始计时之前执行每个操作之一 - 我不确定这是否有必要,但我认为这意味着 JITter 预先生成代码而不是在我们计时时生成代码?
- 多次执行每个操作,而不仅仅是一次。
- 更改顺序以防万一。
在我的机器上,这导致 ~350msCast
和 ~18000ms OfType
。
我认为最大的不同是我们不再MatchCollection
计算找到下一场比赛需要多长时间。(或者,在我的代码中,需要多长时间int.ToString()
。)这大大降低了信噪比。
编辑:正如sixlettervariables 指出的那样,造成这种巨大差异的原因是,Cast
如果它可以投射整个IEnumerable
. 当我从使用切换Regex.Matches
到数组以避免测量正则表达式处理时间时,我也切换到使用可转换的东西IEnumerable<string>
,从而激活了这种短路。当我改变我的基准以禁用这种短路时,我获得了一点优势,Cast
而不是一个巨大的优势。