1

我正在使用 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;
    }
4

2 回答 2

1

我会避免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();

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

于 2015-04-09T01:27:05.717 回答
1

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

请参阅 MSDN 并行选项

于 2015-04-09T01:17:55.410 回答