我查看了一个同事代码并告诉他出于性能原因重新排序以下Linq Any
谓词中的布尔比较。所以给出了
public class JobResult
{
public JobResult();
public string Id{ get; set; }
public StatusEnum Status{ get; set; }
public string JobType{ get; set; }
}
和
IList<JobResult> jobsList = _jobRepository.FetchJobs()
我建议更改以下内容:
//Exit if there is already a job of type "PurgeData" running
if (jobsList.Any(job => job.Status == JobStatus.Running //1
&& job.Id != currentJobId //2
&& job.JobType == "PurgeData")) //3
return false;
成为
//Exit if there is already a job of type "PurgeData" running
if (jobsList.Any(job => job.JobType == "PurgeData" //3
&& job.Status == JobStatus.Running //1
&& job.Id != currentJobId)) //2
return false;
我的理由是jobsList
中的大多数作业都未能通过JobType
的测试,只有少数会失败Running
的测试,只有一个会因Id
的测试失败而失败1}}。如果匹配失败,则无法评估其他匹配,因为序列点不会发生这种情况。
我的三个部分问题是:这是真的,是否可以证明是真的,我可以给我的同事一个更好的解释,为什么重新排序是一个好主意?
答案 0 :(得分:7)
我的理由是,jobList中的大多数作业都无法通过JobType测试,只有少数会因运行测试失败而且只有一个会使Id的测试失败。如果匹配失败,则无法评估其他匹配,并且由于序列点不会发生这种情况。这是真的吗?
第一个是否为假时,第二个和第三个谓词是否会被评估?是。你的推理是正确的。
当第一个假设是假的时候避免评估第二个和第三个谓词是否真的是一个明显的表现胜利? 不一定,原因有两个。
首先,并非所有比较都同样昂贵。比较字符串“PurgeData”和“PurgeDatz”需要在挽救之前比较八个字符;比较整数更便宜。在平均情况下,避免字符串比较可能更便宜,即使它更可能是错误的。
其次,请记住,避免运行代码会消除代码的成本,但您必须编写代码才能测试是否应该避免使用其他代码。测试很便宜但不是免费的!在某些情况下,避免代码实际上比仅仅运行它更昂贵。
请参阅我最近关于此主题的文章:
http://ericlippert.com/2015/11/02/when-would-you-use-on-a-bool/
我可以给我的同事一个更好的解释,为什么重新排序是一个好主意?
是。您可以设置性能指标和实际,重要的以客户为中心的性能目标,您可以凭经验证明代码在根据指标进行衡量时无法满足您的目标,并且您可以凭经验证明代码符合您的目标你用另一种方式写它。
如果你不这样做那么你所描述的是你无法衡量的差异,没有人关心;你的同事告诉你不要浪费时间改变工作代码,以便有所作为,你无法衡量无人关心的事情。
答案 1 :(得分:4)
我的理由是,jobList中的大多数作业都无法通过JobType测试,只有少数会因运行测试失败而且只有一个会使Id的测试失败。如果匹配失败,则无法评估其他匹配,因为序列点不会发生这种情况。
是的,C#中的||
和&&
运算符short-circut。意思是,如果条件已经满足,他们将不会继续评估其他表达式。鉴于JobType
评估为false
,其他谓词将不会被计算。请注意,您的代码可能会有额外的开销,超过这些谓词的重新排序,例如int
与string
的比较(后者最有可能更贵)。
这确实属于微优化的范畴,除了向您的同事解释什么是短路之外,我建议您实际测试此代码以查看它是否提供任何性能优势所有
答案 2 :(得分:4)
就个人而言,我不会太介意这一点。使用LINQ的开销远远超过比较本身。如果第一个谓词评估为false,则忽略所有其他谓词,因此首先测试最不可能的是一个好主意。
继续评估的昂贵,枚举是整数,因此比较枚举比评估整个字符串便宜。第二个评估也是一个整数,所以比比较一个字符串少。我认为string
首先比较长度,所以这也是一个整数比较,比较每个角色的成本更高。因此,如果字符串与其比较的位置相同,则字符串的评估比整数更重。否则它没关系太多。
答案 3 :(得分:0)
很容易浪费时间来优化不慢的事情。
如果你不得不问哪种方法更快,你就无法区分(即两者都足够快)。
Linq查询有时会转换为SQL,因此速度可能取决于数据库的内部实现,这是您无法控制的。