我正在使用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;
}
答案 0 :(得分:1)
Parallel.For的ParallelOptions属性有一个CancellationToken属性,你可以传递它,所以当取消令牌被取消时,parallel for for会停止并产生OperationCanceledException。
答案 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安全的,并且可以轻松取消。