跳出使用LINQ查询的Parallel.ForEach循环

4
我正在使用Parallel.ForEach循环遍历LINQ to SQL映射。一旦处理了一定数量的元素,我就跳出循环。处理停止,但是循环会在几秒钟后挂起,然后我会收到以下错误信息:System.Data.SqlClient.SqlErrorCollection: Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding.如何使循环正常退出?追加查询时强制执行本地集合(例如ToList())不可行。我还尝试将所有内容包装在using块中,但无济于事。请注意,

以下是代码:
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
3个回答

5
您可以使用CancellationTokenSource类的实例来取消并行循环。更多信息请参考:如何取消Parallel.For或ForEach循环 需要注意的重要事项是,当取消标记在并行循环内调用时,已经运行的迭代的执行不会被停止。只是不会启动任何新的迭代。
还有其他方法可以使用ParallelLoopState类的Break()和Stop()方法来中断/停止并行循环。在初始化Parallel.For/ForEach循环时,您可以传递ParallelLoopState类的实例,并使用该实例调用Break/Stop方法。
Break方法的行为与Stop略有不同。在停止的情况下,框架请求尽快停止迭代。使用Break方法,框架请求循环尽快停止当前迭代之后的迭代的执行。如果您正在寻找特定的键/文本,并且希望在找到后立即退出,则应使用Stop()方法。

0

尽管状态Break是停止并行循环的两种方式之一,但是从委托中退出对循环执行没有任何影响,因为每次执行时委托体都与循环结构断开连接。这就解释了为什么您会观察到它在一段时间内挂起(我同意,乍一看似乎Break与我们在循环结构中习惯的语义不同,这是有违直觉的)。循环仍在运行!

解决方案将取决于您在循环中试图实现什么,但您可能需要尝试...

if (pLoopState.ShouldExitCurrentIteration)
{
     return;
}

使用“继续”代替“中断”。这样可以让程序跳过看似卡住的部分。


调用Break,不会停止当前正在运行的迭代索引之前的迭代执行。例如,如果在索引号20上调用Break,则循环将一直执行,直到完成1-19的所有迭代。是的,我同意检查“ShouldExitCurrentIteration”肯定有助于提高响应能力。如果您想在满足某些条件时立即退出,则Stop()是最好的选择。 - Pawan Mishra
探测 pLoopState.ShouldExitCurrentIteration 没有帮助,错误仍然存在。请注意,我已编辑原帖。即使错误相同,我实际上是遍历映射本身 :-/ - OG Dude

0

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

LINQ在尝试枚举其结果时执行查询,而不是在尝试访问其中一个结果时执行。在你的例子中,这是当你将query变量传递给Parallel.ForEach并将其转换为IEnumerable时发生的。然后,Parallel.ForEach接受每个结果行并尝试并行处理它们。

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

Parallel.ForEach(query.Take(10),

不要仅仅传递 查询,而应该在语句中限制返回的行数。

如果您想通过 SQL 或 LINQ 语句限制返回的行数,应该在语句中进行限制,而不是尝试在结果返回后限制结果。检索不必要的行会导致 DB 服务器显著减慢并可能导致死锁。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接