【问题标题】:How to stop multiple Parallel.For loops with CancellationToken如何使用 CancellationToken 停止多个 Parallel.For 循环
【发布时间】:2015-04-09 01:03:57
【问题描述】:

我正在使用 C# 和 WPF 开发应用程序。我正在使用 3 个嵌套的 Parallel.For 循环,如下所示。当我Cancel() 令牌时,循环开始抛出ImportAbortedException 但是,我无法捕捉ImportAbortedException。我咳的是AggregateException

我想要的是,停止所有 Parallel.Fors 并抓住 ImportAbortedException 并做一些其他的事情。

这里是代码。

    private int _loopCount1 = 100;
    private int _loopCount2 = 200;
    private int _loopCount3 = 10000;
    private CancellationToken _cToken;
    private CancellationTokenSource _cSource;
    private void Init()
    {
        _cSource = new CancellationTokenSource();
        _cToken = new CancellationToken();
        _cToken = _cSource.Token;

        try
        {
            DoTheWork();
        }
        catch (ImportAbortedException)
        {
            /// 
        }
        catch (Exception)
        {

        }
    }

    private void StopAllLoops()
    {
        _cSource.Cancel();
    }

    private void DoTheWork()
    {
        Parallel.For(0, _loopCount1, i =>
        {
            if (CheckIfCanceled())
                throw new ImportAbortedException("process aborted!");

            // do a few calculations here.

            Parallel.For(0, _loopCount2, j =>
            {
                if (CheckIfCanceled())
                    throw new ImportAbortedException("process aborted!");

                // do a few calculations here.

                Parallel.For(0, _loopCount3, k =>
                {
                    if (CheckIfCanceled())
                        throw new ImportAbortedException("process aborted!");

                    // do some other process here.
                });
            });
        });
    }

    private bool CheckIfCanceled()
    {
        return _cToken.IsCancellationRequested;
    }

【问题讨论】:

  • 取消任务是很正常的操作。为什么首先抛出异常?
  • 因为我想了解是计算进度抛出异常还是导入取消。

标签: c# wpf parallel.for


【解决方案1】:

Parallel.For 的 ParallelOptions 属性有一个 CancellationToken 属性,您可以传递它,因此当取消标记被取消时,并行 for 将停止并产生 OperationCanceledException。

See MSDN ParallelOptions

【讨论】:

  • 所以,你说我无法捕获 ImportAbortedException。我只能捕获 CancellationToken 引发的异常吗? (OperationCanceledException)
  • 您可以捕获 ImportAbortedException 但您为什么不想使用内置功能来取消操作?您可以共享 ParallelOptions 选项,这样会减少很多代码。
  • 我放弃了使用 ImportAbortedException 的想法,并遵循了您的解决方案。谢谢!
【解决方案2】:

我会完全避免使用Parallel.For,而是使用微软的响应式框架(NuGet "Rx-Main" & "Rx-WPF")。您可以使用它来巧妙地处理所有并行处理,并且可以将结果编组回 UI 线程。

您的代码如下所示:

private IDisposable DoTheWork()
{
    var query =
        from i in Observable.Range(0, _loopCount1)
        from x in Observable.Start(() => SomeCalculation1(i))
        from j in Observable.Range(0, _loopCount2)
        from y in Observable.Start(() => SomeCalculation2(i, j))
        from k in Observable.Range(0, _loopCount3)
        from z in Observable.Start(() => SomeCalculation3(i, j, k))
        select new { x, y, z };

    return
        query
            .ObserveOnDispatcher()
            .Subscribe(w =>
            {
                /* Do something with w.x, w.y, w.z */
            });
}

你可以这样称呼它:

var subscription = DoTheWork();

要取消,您只需这样做:

subscription.Dispose();

这都是多线程的,用户界面安全,并且可以轻松取消。

【讨论】:

  • 感谢您的回答,但我更喜欢使用 Parallel.For。因为所有的项目都已经编写和测试过了。这就是为什么我不能做出巨大的改变:(
  • @cKNet - 不用担心,但你必须同意 Rx 这样做的方式非常好。
猜你喜欢
  • 2019-12-13
  • 1970-01-01
  • 1970-01-01
  • 2017-01-26
  • 2015-09-13
  • 1970-01-01
  • 2018-05-13
  • 1970-01-01
  • 2016-03-10
相关资源
最近更新 更多