【发布时间】:2016-10-27 12:52:58
【问题描述】:
我有一个线程定期检查我的一个 MS SQL 表中是否有任何将“已处理”位字段设置为 0 的记录。该线程然后使用这些记录执行一些代码,然后将它们的已处理位设置为 1;基本上将其用作队列。我用来检索这些记录的 Linq 查询跨越多行并且非常复杂(原因与问题无关),所以这里是一个非常简化的版本:
var RecordsToProcess = MyTable.Where(i => i.Processed == 0); // Very simplified
我需要等到所有记录都处理完才能继续,所以我想使用这样的东西:
while (RecordsToProcess.Count() > 0)
{
System.Threading.Thread.Sleep(1000);
}
问题在于,虽然线程实际上确实处理了记录并将它们的已处理位设置为 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() 会将该整数存储在内存中”——IIRC 第一次调用
RecordsToProcess.Count()时,会评估RecordsToProcess,并缓存该评估的结果.所以实际上,你是对的。我的解决方案是var count = MyTable.Where().Blah().Blah().Long().Query(),带有适当的换行符等以提高可读性,然后是if (count > 0) { ... }——或者在GetProcessedRecords()方法中隐藏LINQ。 -
一切最终都取决于您的
RecordsToProcess查询。您应该向我们展示该查询是什么。您可能以已经评估过的方式编写它。 -
当然我看不到你的其余代码,但你不能等待线程完成吗?或者甚至不在另一个线程中这样做?
标签: c# multithreading linq linq-to-sql deferred-execution