Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何使用Linq';条件语句中的s.Count()方法_C#_Multithreading_Linq_Linq To Sql_Deferred Execution - Fatal编程技术网

C# 如何使用Linq';条件语句中的s.Count()方法

C# 如何使用Linq';条件语句中的s.Count()方法,c#,multithreading,linq,linq-to-sql,deferred-execution,C#,Multithreading,Linq,Linq To Sql,Deferred Execution,我有一个线程,它定期检查我的一个MS SQL表中是否有“已处理”位字段设置为0的记录。然后线程使用这些记录执行一些代码,然后将它们的处理位设置为1;基本上将其用作队列。我用来检索这些记录的Linq查询跨越多行,而且非常复杂(原因与问题无关),因此这里有一个非常简化的版本: var RecordsToProcess = MyTable.Where(i => i.Processed == 0); // Very simplified 我需要等到所有记录都处理完毕后再继续,因此我想使用如下方式

我有一个线程,它定期检查我的一个MS SQL表中是否有“已处理”位字段设置为0的记录。然后线程使用这些记录执行一些代码,然后将它们的处理位设置为1;基本上将其用作队列。我用来检索这些记录的Linq查询跨越多行,而且非常复杂(原因与问题无关),因此这里有一个非常简化的版本:

var RecordsToProcess = MyTable.Where(i => i.Processed == 0); // Very simplified
我需要等到所有记录都处理完毕后再继续,因此我想使用如下方式:

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

问题是,虽然线程实际上处理记录并将其处理位设置为1,但条件语句中RecordStopProcess.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
,都会重新求值。在第二个示例中,整个查询都在循环中,因此每次都必须重新计算,而不管is是否实际使用延迟计算。我会检查MSDN文档中有关您正在使用的操作员的
备注

我还建议在这种情况下使用
Any
而不是
Count
,以提高性能和清晰度。根据迭代的内容,
Count
通常会迭代一个集合以查看有多少个元素,但是
Any
更懒。在LINQ to对象中,
Count()
针对实现
ICollection
的序列进行了优化,以使用
Count
属性,该属性比迭代快得多,并且
Any()
在找到1个元素后停止检查。正如下面Erik所建议的,在LINQtoSQL中,很可能在
SELECT
语句中添加了类似于
TOP1
的内容。我假设SQL有自己的
COUNT
优化,但我没有做任何研究

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

我会像这样实现您的方法:

while (RecordsToProcess.Count() > 0)
{
    System.Threading.Thread.Sleep(1000);
}
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); }

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

根据评论编辑原始帖子。

我相信问题的一部分是编译器如何优化循环

很可能是查询中缓存数据的内容。如果整个查询使用延迟求值,除了循环中检查的
Count
,那么每次调用查询上的
Count
,都会重新求值。在第二个示例中,整个查询都在循环中,因此每次都必须重新计算,而不管is是否实际使用延迟计算。我会检查MSDN文档中有关您正在使用的操作员的
备注

我还建议在这种情况下使用
Any
而不是
Count
,以提高性能和清晰度。根据迭代的内容,
Count
通常会迭代一个集合以查看有多少个元素,但是
Any
更懒。在LINQ to对象中,
Count()
针对实现
ICollection
的序列进行了优化,以使用
Count
属性,该属性比迭代快得多,并且
Any()
在找到1个元素后停止检查。正如下面Erik所建议的,在LINQtoSQL中,很可能在
SELECT
语句中添加了类似于
TOP1
的内容。我假设SQL有自己的
COUNT
优化,但我没有做任何研究

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

我会像这样实现您的方法:

while (RecordsToProcess.Count() > 0)
{
    System.Threading.Thread.Sleep(1000);
}
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); }

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

您没有刷新每个循环上的RecordStopProcess变量

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

您没有刷新每个循环上的RecordStopProcess变量

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

“我猜调用.Count()会将该整数存储在内存中”-IIRC第一次调用
RecordsToProcess.Count()
,将对
RecordsToProcess
进行求值,并缓存求值结果。实际上,你是对的。我的解决方案是
var count=MyTable.Where().Blah().Blah().Long().Query()
带有适当的换行符等,以确保可读性,然后是
if(count>