我的代码中遇到了一个相当愚蠢的性能问题。经过一个小小的调查,我发现我用来构建我的通用列表的AsQueryable方法减慢了代码的速度达8000倍。 所以问题是,为什么呢? 这是示例
class Program
{
static void Main(string[] args)
{
var c = new ContainerTest();
c.FillList();
var s = Environment.TickCount;
for (int i = 0; i < 10000; ++i)
{
c.TestLinq(true);
}
var e = Environment.TickCount;
Console.WriteLine("TestLinq AsQueryable - {0}", e - s);
s = Environment.TickCount;
for (int i = 0; i < 10000; ++i)
{
c.TestLinq(false);
}
e = Environment.TickCount;
Console.WriteLine("TestLinq as List - {0}", e - s);
Console.WriteLine("Press enter to finish");
Console.ReadLine();
}
}
class ContainerTest
{
private readonly List<int> _list = new List<int>();
private IQueryable<int> _q;
public void FillList()
{
_list.Clear();
for (int i = 0; i < 10; ++i)
{
_list.Add(i);
}
_q = _list.AsQueryable();
}
public Tuple<int, int> TestLinq(bool useAsQ)
{
var upperBorder = useAsQ ? _q.FirstOrDefault(i => i > 7) : _list.FirstOrDefault(i => i > 7);
var lowerBorder = useAsQ ? _q.TakeWhile(i => i < 7).LastOrDefault() : _list.TakeWhile(i => i < 7).LastOrDefault();
return new Tuple<int, int>(upperBorder, lowerBorder);
}
}
UPD据我所知,我必须尽可能避免AsQueryable方法(如果它不在容器的继承行中),因为我会立即 性能问题
“当邪恶的力量被提升时,避免在黑暗的时刻停泊”
答案 0 :(得分:0)
至少使用LINQ with List
手动实现总是比LINQ
更快修改强>
你知道两个测试都没有给出相同的结果
答案 1 :(得分:0)
因为AsQueryable
返回IQueryable
,它对于LINQ标准查询运算符有一组完全不同的扩展方法,用于List
之类的内容。
Queryable
集合意味着拥有RDBMS或类似内容的后备存储,当您调用IQueryable.FirstOrDefault()
而不是{{1}时,您正在构建一个不同的,更复杂的代码表达式树}。
答案 2 :(得分:0)
刚刚遇到同样的问题。
问题是 IQueryable<T>
将 Expression<Func<T, Bool>>
作为参数用于过滤 Where()
/FirstOrDefault()
调用 - 而不仅仅是 Func<T, Bool>
预编译委托采用简单的 IEnumerable
对应方法。
这意味着将有一个编译阶段将 Expression
转换为 delegate
。而这成本相当高。
现在您需要在循环中使用它(我就是这样做的)?你会遇到一些麻烦...
PS:似乎是 .NET Core/.NET 5 improves this significantly。不幸的是,我们的项目还没有...