ThrowIfCancellationRequested似乎没有抛出任何异常

本文关键字:任何 异常 ThrowIfCancellationRequested | 更新日期: 2023-09-27 17:51:02

我有以下代码:

CancellationTokenSource cts = new CancellationTokenSource();
ParallelOptions po = new ParallelOptions();
po.CancellationToken = cts.Token;
Task.Factory.StartNew(() =>
{
     if (Console.ReadKey().KeyChar == 'c')
         cts.Cancel();
     Console.WriteLine("press any key to exit");
});
 Parallel.ForEach(list, po, (algo) =>
 {
      algo.Compute(); // this compute lasts 1 minute  
      Console.WriteLine("this job is finished");       
      po.CancellationToken.ThrowIfCancellationRequested();
 });

list包含的元素很少。当我按下'c'时,所有Compute方法都已启动。

当我按下'c'时,不会抛出异常。每个Compute方法继续执行,直到正常结束。

当我按下'c'时,我想停止/杀死所有剩余的Compute方法

ThrowIfCancellationRequested似乎没有抛出任何异常

取消不是这样工作的。它不像调用Thread.Abort()来立即终止线程。

对于序列中的每个元素,代码执行:

    调用Compute()方法
  1. 等待完成
  2. 写到控制台完成
  3. 检查是否请求取消,如果是则抛出OperationCanceledException

为了取消一些任务,你需要将CancellationToken传递给被调用的方法。
也许,值得将长时间运行的计算组织为一个循环,并检查是否在每一步都请求取消,以便尽快停止它。

例如,在Compute()方法中,您可以执行这样的检查:

private void Compute(CancellationToken ct)
{
    while (true)
    {
       ComputeNextStep();
       ct.ThrowIfCancellationRequested();
    }
}

观察po.CancellationToken.IsCancellationRequested的取消,并使用ParallelLoopState.Stop来阻止Parallel.ForEach:

void Compute(CancellationToken token, ParallelLoopState loopState)
{
    bool more = true;
    while (more)
    {
        if (token.IsCancellationRequested)
        {
            // stop Parallel.ForEach ASAP
            loopState.Stop();
            return;
        }
        // do the calc step
    }
}
// ... 
CancellationTokenSource cts = new CancellationTokenSource();
ParallelOptions po = new ParallelOptions();
po.CancellationToken = cts.Token;
Task.Factory.StartNew(() =>
{
    if (Console.ReadKey().KeyChar == 'c')
        cts.Cancel();
    Console.WriteLine("press any key to exit");
});
Parallel.ForEach(list, po, (algo, loopState) =>
{
    algo.Compute(po.CancellationToken, loopState); // this compute lasts 1 minute  
    Console.WriteLine("this job is finished");
});
// observe the cancellation again and throw after Parallel.ForEach
po.CancellationToken.ThrowIfCancellationRequested();