如何使用CancellationToken停止多个Parallel.For循环

时间:2015-04-09 01:03:58

标签: c# wpf parallel.for

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

我想要的是,停止所有Parallel.For并抓住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;
    }

2 个答案:

答案 0 :(得分:1)

Parallel.For的ParallelOptions属性有一个CancellationToken属性,你可以传递它,所以当取消令牌被取消时,parallel for for会停止并产生OperationCanceledException。

See MSDN ParallelOptions

答案 1 :(得分:1)

我会完全避免使用Parallel.For并使用Microsoft的Reactive Framework(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();

所有这些都是多线程的,UI安全的,并且可以轻松取消。