如何正确取消Parallel.Foreach?

9

我有一段代码,看起来像这样:

Parallel.Foreach(ItemSource(),(item)=>DoSomething(item));

ItemSource() 产生一个无限的项目流。

我希望循环在满足某些条件后退出,并且我宁愿不在 DoSomething 中抛出异常(我认为这种方法是一种糟糕的编程风格)。

理想情况下,会有像 cancellationToken 这样的东西。我将在一个或多个线程中调用 cancellationToken.Activate(),之后 Parallel.ForEach 将停止创建新线程,并在最后一个线程退出后返回函数。

在 C# 中使用 Parallel.ForEach 是否可以实现这一点,还是应该使用线程代替?

更新 这是 microsoft 建议 我这样做的:

        try
        {
            Parallel.ForEach(nums, po, (num) =>
            {
                double d = Math.Sqrt(num);
                Console.WriteLine("{0} on {1}", d, Thread.CurrentThread.ManagedThreadId);
                po.CancellationToken.ThrowIfCancellationRequested();
            });
        }
        catch (OperationCanceledException e)
        {
            Console.WriteLine(e.Message);
        }

我不喜欢这种方法,因为它涉及在委托内部抛出异常。

2
你不必抛出异常。你可以只是检查 CancellationToken.IsCancellationRequested 属性,然后以任意你想要的方式从方法中返回。 - Trevor Elliott
5
抛出异常的好处是你作为任务的调用者有机会知道它是否被取消。这在返回值的任务范围内最有意义。例如,如果你运行一个返回字符串的任务...你怎么知道是否有错误或取消?你可以返回 null,但如果 null 是这个任务的有效成功结果呢?异常在任务中与常规方法中一样有用。 - Trevor Elliott
据我所知,抛出异常是一种固有的缓慢操作。 - Arsen Zahray
2
哪个更糟糕,代码稍微慢一点还是代码中有未捕获的错误? - Trevor Elliott
2
@ArsenZahray 这都是相对的。与简单的指针操作、内存访问、简单算术等相比,抛出和捕获异常的成本相当昂贵。但与创建新线程、同步多个线程之间的访问、上下文切换等成本相比,异常在这种方法的执行时间中不会占据重要部分。考虑到上下文,像这样的“成本”语句非常重要。 - Servy
那么,你已经看到了如何正确地完成这个任务。你在问什么?如果你想知道应该如何做,你刚刚展示了一个例子。这就是正确的做法。如果你不喜欢,没关系,你完全可以按照自己的方式去做。标准实践并不适合每个人。但是你在这里问什么呢? - Servy
2个回答

22

在Parallel.ForEach中,有一个选项可以创建ParallelLoopState,该状态允许您中断循环:

ParallelOptions po = new ParallelOptions();
po.MaxDegreeOfParallelism = Constants.MaxParallelProcesses;
var drc = Companies.AsEnumerable();

Parallel.ForEach(drc, po, (drcCompany, loopState) =>
{
    //do stuff here
    if(YourBreakCondition) loopState.Break();
}

在这里检查ParallelLoopState http://msdn.microsoft.com/es-es/library/system.threading.tasks.parallelloopstate.aspx


2
为了完整性...除了 Break 之外,还有一个 Stop 方法可供选择。 - Phil Haselden

3
不必调用ThrowIfCancellationRequested(),因为Parallel.For()/Parallel.ForEach()已经在内部执行该操作。 该Microsoft Docs页面将很快更新 - GitHub问题

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