我对这里的结果有些困惑,也许有人可以给我一些见解?
基本上,我正在尝试测试两次使用之间的性能
OfType(x)
Where(_ = _ is x).Select((X)x)
Where(_ = _.Type = type).Select((X)x)
以下是课程:
public enum AnimalTypes { Alligator, Bear, Cat, Dog, Elephant }
public interface IAnimal
{
AnimalTypes Type { get; }
}
public class Bear : IAnimal
{
public AnimalTypes Type => AnimalTypes.Bear;
}
public class Cat : IAnimal
{
public AnimalTypes Type => AnimalTypes.Cat;
}
编辑:此代码已根据注释修复!对不起,这个错误 这是测试方法
void Main()
{
List<IAnimal> animals = new List<IAnimal>();
for (int i = 0; i < 100000; i++)
{
animals.Add(new Bear());
animals.Add(new Cat());
}
// tests
IEnumerable<Cat> test1 = animals.OfType<Cat>();
IEnumerable<Cat> test2 = animals.Where(_ => _ is Cat).Select(_ => (Cat)_);
IEnumerable<Cat> test3 = animals.Where(_ => _.Type == AnimalTypes.Cat).Select(_ => (Cat)_);
Stopwatch sw = new Stopwatch();
// OfType
sw.Start();
test1.ToArray();
sw.Stop();
Console.WriteLine($"OfType = {sw.ElapsedTicks} ticks");
sw.Reset();
// Where (is) + Select
sw.Start();
test2.ToArray();
sw.Stop();
Console.WriteLine($"Where (is) + Select = {sw.ElapsedTicks} ticks");
sw.Reset();
// Where (enum) + Select
sw.Start();
test3.ToArray();
sw.Stop();
Console.WriteLine($"Where (type) + Select = {sw.ElapsedTicks} ticks");
sw.Reset();
}
奇怪的是,结果始终确保最后一次测试获得最佳结果...
答案 0 :(得分:4)
您的测试代码存在三个大问题:
改为查看类似的内容:
var animals = new List<IAnimal>();
for (int i = 0; i < 1000000; i++)
{
animals.Add(new Bear());
animals.Add(new Cat());
}
// remove overhead of the first query
int catsCount = animals.Where(x => x == x).Count();
var whereIsTicks = new List<long>();
var whereTypeTicks = new List<long>();
var ofTypeTicks = new List<long>();
var sw = Stopwatch.StartNew();
// a performance test with a single pass doesn't make a lot of sense
for (int i = 0; i < 100; i++)
{
sw.Restart();
// Where (is) + Select
catsCount = animals.Where(_ => _ is Cat).Select(_ => (Cat)_).Count();
whereIsTicks.Add(sw.ElapsedTicks);
// Where (enum) + Select
sw.Restart();
catsCount = animals.Where(_ => _.Type == AnimalTypes.Cat).Select(_ => (Cat)_).Count();
whereTypeTicks.Add(sw.ElapsedTicks);
// OfType
sw.Restart();
catsCount = animals.OfType<Cat>().Count();
ofTypeTicks.Add(sw.ElapsedTicks);
}
sw.Stop();
// get the average run time for each test in an easy-to-print format
var results = new List<Tuple<string, double>>
{
Tuple.Create("Where (is) + Select", whereIsTicks.Average()),
Tuple.Create("Where (type) + Select", whereTypeTicks.Average()),
Tuple.Create("OfType", ofTypeTicks.Average()),
};
// print results orderer by time taken
foreach (var result in results.OrderBy(x => x.Item2))
{
Console.WriteLine($"{result.Item1} => {result.Item2}");
}
多次运行Where (is)
可能比Where (type)
快一点或慢一点,但是OfType
始终是最慢的,而且有一定优势:
i < 10
:
Where (type) + Select => 111428.9
Where (is) + Select => 132695.8
OfType => 158220.7
i < 100
:
Where (is) + Select => 110541.8
Where (type) + Select => 119822.74
OfType => 150087.22
i < 1000
:
Where (type) + Select => 113196.381
Where (is) + Select => 115656.695
OfType => 160461.465
当您查看源代码for the OfType
method时,OfType
总是变慢的原因很明显:
static IEnumerable<TResult> OfTypeIterator<TResult>(IEnumerable source)
{
foreach (object obj in source)
{
if (obj is TResult)
{
yield return (TResult)obj;
}
}
}
如您所见,源项目使用is
进行了类型检查,然后被投射回TResult
。由于装箱,值类型的差异会更大。