我试图了解在延迟执行的情况下并行性如何使用 PLINQ 工作。这是一个简单的例子。
string[] words = { "believe", "receipt", "relief", "field" };
bool result = words.AsParallel().Any(w => w.Contains("ei"));
使用 LINQ,我希望执行达到“收据”值并返回 true,而不执行对其余值的查询。
如果我们并行执行此操作,则“relief”的评估可能在“receipt”结果返回之前就开始了。但是一旦查询知道“receipt”会产生真实的结果,其他线程会立即屈服吗?
就我而言,这很重要,因为“任何”测试可能非常昂贵,并且我希望释放处理器来执行其他任务。
不幸的是,其他线程不会立即“屈服”。
一旦
Any()
找到有效元素,PLINQ 调度程序将停止调度新线程来检查新元素。任何现有的分区程序也将收到取消请求,这将阻止这些分区在另一个项目上调用 Any()
。
但是,当前在您的 Any()
方法中执行 lambda 表达式的任何线程仍将执行,因为它们无法知道另一个线程已成功。它将阻止新线程调用
Any()
,但不会取消“非常昂贵”委托中的所有线程。附注:
PLINQ 与 LINQ to Objects 不同,它并不真正使用延迟执行。当您在
AsParallel()
上调用
IEnumerable<T>
时,生成的 ParallelQuery<T>
实际上将开始并行处理您的例程。延迟执行会极大地降低 PLINQ 的有效性,因为如果不提前创建工作分区和调度,就不可能并行调度。
编辑:考虑到这一点后 - 如果您的 lambda 非常昂贵,您可能需要考虑使用
CancellationToken。我在博客中详细介绍了PLINQ 中的取消如何工作。通常,您只需使用令牌并调用 ThrowIfCancellationRequested() - 但是,您也可以使用 CancellationToken 并检查 IsCancellationRequested,这将使您的 lambda“提前退出”,为您提供一种停止后台处理更快...