我今天在我的项目中看到了一个 LINQ 查询语法,它正在计算 List 中具有特定条件的项目,如下所示:
int temp = (from A in pTasks
where A.StatusID == (int)BusinessRule.TaskStatus.Pending
select A).ToList().Count();
我想通过使用 Count(Func) 重写它来重构它以使其更具可读性。我认为这在性能方面也会很好,所以我写道:
int UnassignedCount = pTasks.Count(x => x.StatusID == (int)BusinessRule.TaskStatus.Pending);
但是当我使用 StopWatch 检查时,lambda 表达式耗时总是比查询语法多:
Stopwatch s = new Stopwatch();
s.Start();
int UnassignedCount = pTasks.Count(x => x.StatusID == (int)BusinessRule.TaskStatus.Pending);
s.Stop();
Stopwatch s2 = new Stopwatch();
s2.Start();
int temp = (from A in pTasks
where A.StatusID == (int)BusinessRule.TaskStatus.Pending
select A).ToList().Count();
s2.Stop();
谁能解释一下为什么会这样?
最佳答案
我模拟了你的情况。是的,这些查询的执行时间是不同的。但是,这种差异的原因不是查询的语法。使用方法或查询语法并不重要。两者都会产生相同的结果,因为在编译之前,查询表达式会被翻译成它们的 lambda 表达式。
但是,如果您注意到这两个查询根本不相同。您的第二个查询将在编译之前转换为它的 lambda 语法(您可以删除 ToList() 来自查询,因为它是多余的):
pTasks.Where(x => x.StatusID == (int)BusinessRule.TaskStatus.Pending).Count();
现在我们有两个 lambda 语法的 Linq 查询。我上面提到的那个和这个:
pTasks.Count(x => x.StatusID == (int)BusinessRule.TaskStatus.Pending);
现在,问题是:
为什么这两个查询的执行时间不同?
让我们找出答案:
我们可以通过回顾这些来理解这种差异的原因:
- .Where(this IEnumerable<TSource> source, Func<TSource, bool> predicate).Count(this IEnumerable<TSource> source)
和
- Count(this IEnumerable<TSource> source, Func<TSource, bool> predicate) ;
这里是 Count(this IEnumerable<TSource> source, Func<TSource, bool> predicate) 的实现:
public static int Count<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
if (source == null) throw Error.ArgumentNull("source");
if (predicate == null) throw Error.ArgumentNull("predicate");
int count = 0;
foreach (TSource element in source) {
checked {
if (predicate(element)) count++;
}
}
return count;
}
这里是 Where(this IEnumerable<TSource> source, Func<TSource, bool> predicate) :
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
if (source == null)
throw Error.ArgumentNull("source");
if (predicate == null)
throw Error.ArgumentNull("predicate");
if (source is Iterator<TSource>)
return ((Iterator<TSource>)source).Where(predicate);
if (source is TSource[])
return new WhereArrayIterator<TSource>((TSource[])source, predicate);
if (source is List<TSource>)
return new WhereListIterator<TSource>((List<TSource>)source, predicate);
return new WhereEnumerableIterator<TSource>(source, predicate);
}
关注Where()执行。它将返回 WhereListIterator()如果你的收藏是 List,但是 Count()只会遍历源。
在我看来,他们在 implementation 中做了一些加速的 WhereListIterator .之后我们调用Count()该方法不采用谓词作为输入,只会迭代过滤后的集合。
关于 WhereListIterator 的执行速度:
我找到了 this SO 中的问题: LINQ performance Count vs Where and Count 。你可以阅读@Matthew Watson answer那里。他解释了这两个查询之间的性能差异。结果是:
来自书 When the callvirt IL instruction is used to call a virtual instance
method, the CLR discovers the actual type of the object being used to
make the call and then calls the method polymorphically. In order to
determine the type, the variable being used to make the call must not
be null. In other words, when compiling this call, the JIT compiler
generates code that verifes that the variable’s value is not null. If
it is null, the callvirt instruction causes the CLR to throw a
NullReferenceException. This additional check means that the callvirt
IL instruction executes slightly more slowly than the call
instruction.Where迭代器避免了间接调用虚表,而是直接调用迭代器方法。
正如您在该答案中看到的 call将发出指令而不是 callvirt .而且,callvirt比 call 慢:CLR via C# :
关于c# - LINQ Lambda 与查询语法性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28576999/
我正在用Ruby编写一个简单的程序来检查域列表是否被占用。基本上它循环遍历列表,并使用以下函数进行检查。require'rubygems'require'whois'defcheck_domain(domain)c=Whois::Client.newc.query("google.com").available?end程序不断出错(即使我在google.com中进行硬编码),并打印以下消息。鉴于该程序非常简单,我已经没有什么想法了-有什么建议吗?/Library/Ruby/Gems/1.8/gems/whois-2.0.2/lib/whois/server/adapters/base.
我脑子里浮现出一些关于一种新编程语言的想法,所以我想我会尝试实现它。一位friend建议我尝试使用Treetop(Rubygem)来创建一个解析器。Treetop的文档很少,我以前从未做过这种事情。我的解析器表现得好像有一个无限循环,但没有堆栈跟踪;事实证明很难追踪到。有人可以指出入门级解析/AST指南的方向吗?我真的需要一些列出规则、常见用法等的东西来使用像Treetop这样的工具。我的语法分析器在GitHub上,以防有人希望帮助我改进它。class{initialize=lambda(name){receiver.name=name}greet=lambda{IO.puts("He
所以我在关注Railscast,我注意到在html.erb文件中,ruby代码有一个微弱的背景高亮效果,以区别于其他代码HTML文档。我知道Ryan使用TextMate。我正在使用SublimeText3。我怎样才能达到同样的效果?谢谢! 最佳答案 为SublimeText安装ERB包。假设您安装了SublimeText包管理器*,只需点击cmd+shift+P即可获得命令菜单,然后键入installpackage并选择PackageControl:InstallPackage获取包管理器菜单。在该菜单中,键入ERB并在看到包时选择
我知道我可以指定某些字段来使用pluck查询数据库。ids=Item.where('due_at但是我想知道,是否有一种方法可以指定我想避免从数据库查询的某些字段。某种反拔?posts=Post.where(published:true).do_not_lookup(:enormous_field) 最佳答案 Model#attribute_names应该返回列/属性数组。您可以排除其中一些并传递给pluck或select方法。像这样:posts=Post.where(published:true).select(Post.attr
在Ruby类中,我重写了三个方法,并且在每个方法中,我基本上做同样的事情:classExampleClassdefconfirmation_required?is_allowed&&superenddefpostpone_email_change?is_allowed&&superenddefreconfirmation_required?is_allowed&&superendend有更简洁的语法吗?如何缩短代码? 最佳答案 如何使用别名?classExampleClassdefconfirmation_required?is_a
如何在ruby中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL
我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha
可能已经问过了,但我找不到它。这里有2个常见的情况(对我来说,在编程Rails时......)用ruby编写是令人沮丧的:"astring".match(/abc(.+)abc/)[1]在这种情况下,我得到一个错误,因为字符串不匹配,因此在nil上调用[]运算符。我想找到的是比以下内容更好的替代方法:temp="astring".match(/abc(.+)abc/);temp.nil??nil:temp[1]简而言之,如果不匹配,则简单地返回nil而不会出错第二种情况是这样的:var=something.very.long.and.tedious.to.writevar=some
我正在学习Ruby的基础知识(刚刚开始),我遇到了Hash.[]method.它被引入a=["foo",1,"bar",2]=>["foo",1,"bar",2]Hash[*a]=>{"foo"=>1,"bar"=>2}稍加思索,我发现Hash[*a]等同于Hash.[](*a)或Hash.[]*一个。我的问题是为什么会这样。是什么让您将*a放在方括号内,是否有某种规则可以在何时何地使用“it”?编辑:我的措辞似乎造成了一些困惑。我不是在问数组扩展。我明白了。我的问题基本上是:如果[]是方法名称,为什么可以将参数放在括号内?这看起来几乎——但不完全是——就像说如果你有一个方法Foo.d
C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.