.net 在LINQ查询上突破Parallel.ForEach

.net 在LINQ查询上突破Parallel.ForEach,.net,linq-to-sql,task-parallel-library,.net,Linq To Sql,Task Parallel Library,我使用Parallel.ForEach在LINQ到SQL映射上循环。一旦处理了一定数量的元素,我就打破了循环。处理停止,但循环随后会挂起几秒钟,直到出现错误: System.Data.SqlClient.SqlErrorCollection:超时已过期。操作完成前超时或服务器没有响应。 如何使循环正常退出?通过将say aToList()附加到查询来强制本地收集不是选项。我还尝试使用块将所有内容包装在中,但没有成功。请注意 代码如下: var query = SomeDataContext.So

我使用
Parallel.ForEach
在LINQ到SQL映射上循环。一旦处理了一定数量的元素,我就打破了循环。处理停止,但循环随后会挂起几秒钟,直到出现错误:

System.Data.SqlClient.SqlErrorCollection:超时已过期。操作完成前超时或服务器没有响应。

如何使循环正常退出?通过将say a
ToList()
附加到查询来强制本地收集不是选项。我还尝试使用块将所有内容包装在
中,但没有成功。请注意

代码如下:

var query = SomeDataContext.SomeTableMapping; // All ok, if I append Take(maxRecords)
int maxRecords = 1000;
Parallel.ForEach(query, (queryResult, pLoopState, idx) =>
{
    // Do whatever here on queryResult.
    if (idx > maxRecords)
    {
         Console.WriteLine("Reached maximum number of records: {0}", maxRecords);
         pLoopState.Break();
    }
});
谢谢


/David

您可以使用CancellationTokenSource类实例来取消并行循环。更多信息:

这里需要注意的重要一点是,当在并行循环中调用取消令牌in时,已经运行的迭代的执行将不会停止。只是任何新的迭代都不会开始

使用ParallelLoopState类的Break()和Stop()方法还有其他中断/停止并行循环的方法。初始化Parallel.For/ForEach循环时,可以传递ParallelLoopState类的实例,并使用该实例调用Break/Stop方法


“中断”方法的行为与“停止”略有不同。在Stop的情况下,框架请求尽快停止迭代。使用Break,框架请求循环尽快停止当前迭代之外的迭代的执行。如果要查找特定的键/文本,并且希望在找到后立即断开,则应使用Stop()方法。

即使状态断开是停止并行循环的两种方法之一,中断委托不会对循环执行产生任何影响,因为每次执行时委托体都会与循环结构断开连接。这就解释了为什么你会观察它一段时间(我也同意,第一眼看到它似乎是违反直觉的,即中断与我们在循环构造中习惯的语义不同)。循环仍在运行

解决方案将取决于您试图在循环中完成的内容,但您可能希望尝试

if (pLoopState.ShouldExitCurrentIteration)
{
     return;
}

而不是休息。这应该能让你通过它看起来悬挂的部分

您可能应该检查正在执行的SQL语句,而不是循环。循环将并行处理语句返回的所有行。跳出循环不会停止语句的执行,它只会停止对结果的处理

LINQ在您尝试枚举其结果时执行查询,而不是在您尝试访问其中一个结果时执行查询。在您的示例中,这是将查询变量传递给Parallel.ForEach并将其转换为IEnumerable的时刻。然后,Parallel.ForEach获取每个结果行并尝试并行处理它

我怀疑您查询的表很大,没有任何WHERE条件。因此,一旦默认执行超时时间过去(我想大约60秒),您的连接就会超时。如果要检索特定数量的行,应在SQL中使用e TOP语句或在LINQ中使用Take()方法,例如通过调用

Parallel.ForEach(query.Take(10),
而不是简单地传递查询


如果要限制SQL或LINQ语句返回的行,则应在语句本身中执行此操作,而不是在返回结果后尝试限制结果。检索不必要的行结果将显著降低数据库服务器的速度,并可能导致死锁。

调用Break不会停止执行小于当前运行的迭代索引的迭代。假设在索引号20上调用Break,那么循环将不会停止,直到从1到19的所有迭代都完成。是的,我同意检查“ShouldExitCurrentIteration”肯定会有助于提高响应能力。如果您想在满足某个条件后立即爆发,那么Stop()是您的最佳选择。探测
pLoopState.ShouldExitCurrentIteration
没有帮助,错误仍然存在。请注意,我编辑了我的原始帖子。我实际上迭代了映射本身,即使错误是相同的:-/