如何使用林克的 .条件语句中的 Count() 方法



我有一个线程,定期检查我的MS SQL表中的任何记录,他们的"Processed"位字段设置为0。然后线程使用这些记录执行一些代码,然后将它们的Processed位设置为1;把它当作一个队列。我用来检索这些记录的Linq查询跨越多行并且相当复杂(原因与问题无关),因此这里是一个非常简化的版本:

var RecordsToProcess = MyTable.Where(i => i.Processed == 0); // Very simplified

在继续之前,我需要等待所有的记录都被处理,所以我想使用这样的东西:

while (RecordsToProcess.Count() > 0)
{
    System.Threading.Thread.Sleep(1000);
}

问题是,虽然线程实际上处理记录并将其Processed位设置为1,但条件语句中的RecordsToProcess.Count()的值永远不会减少,因此我们得到一个无限循环。我的猜测是,调用. count()将该整数存储在内存中,然后循环的每次迭代都查看该值,而不是查询数据库以获得当前计数。我可以通过将查询移动到条件语句中来获得我想要的行为,如下所示:

while (true)
{
    if (MyTable.Where(i => i.Processed == 0).Count() > 0)
        System.Threading.Thread.Sleep(1000);
    else
        break;
}

由于我实际使用的查询比这个例子中的查询复杂得多,因此这样做会使其难以阅读。是否有一些我可以使用,这是类似于RecordsToProcess.Count()> 0,但查询数据库的每次迭代,而不是使用存储在内存中的初始计数(假设我是正确的)?

注意:我通常不会使用这样一个有潜在危险的while循环,但我只需要运行这个页面最多4或5次,然后再也不运行了。所以我不太担心。

根据评论编辑原文

我认为部分问题在于编译器如何优化循环。

很可能是您的查询中的某些内容正在缓存数据。如果整个查询使用延迟求值,除了在循环中检查Count外,每次在查询中调用Count时,它都会被重新求值。在第二个示例中,整个查询都在循环中,因此每次都必须重新求值,而不管它是否实际上使用延迟求值。我会检查MSDN文档中关于您正在使用的操作符的remarks

为了性能和清晰度,我还建议在这种情况下使用Any而不是Count。根据迭代的内容,Count通常会遍历集合以查看有多少元素,但Any更懒惰。在LINQ to Object中,Count()针对实现ICollection的序列进行了优化,使用Count属性,这比迭代快得多,Any()在找到1个元素后停止检查。正如Erik下面建议的那样,在LINQ to SQL中,可能会有类似TOP 1的东西添加到SELECT语句中。我认为SQL有自己的COUNT优化,但我没有做任何研究。

在适当的时候使用Any()还可以通过去掉Count() > 0中的运算符来帮助提高可读性,并且更清楚地表达您对bool而不是int感兴趣。

我将这样实现你的方法:

var query = MyTable.Where(i => i.Processed == 0);
while(true) {
    if (!query.Any()) break;
    Thread.Sleep(1000);
}

或者更好,如果你能让它延迟执行:

var query = MyTable.Where(i => i.Processed == 0);
while(query.Any()) { Thread.Sleep(1000); }

但是,正如其他答案所提到的,更多关于如何构造查询的信息将会有所帮助。

您没有在每个循环上刷新RecordsToProcess变量

While(RecordsToProcess.Count() > 0)
{
  System.Threading.Thread.Sleep(1000);
  RecordsToProcess = MyTable.Where(i => i.Processed == 0);
}

相关内容

  • 没有找到相关文章

最新更新