取消任务的另一种方法

本文关键字:方法 另一种 任务 取消 | 更新日期: 2023-09-27 17:57:14

我有一个简单的控制台应用程序

class Program
{
    private static void MyTask(object obj)
    {
        var cancellationToken = (CancellationToken) obj;
        if(cancellationToken.IsCancellationRequested)
            cancellationToken.ThrowIfCancellationRequested();
        Console.WriteLine("MyTask() started");
        for (var i = 0; i < 10; i++)
        {
            try
            {
                if (cancellationToken.IsCancellationRequested)
                    cancellationToken.ThrowIfCancellationRequested();
            }
            catch (Exception ex)
            {
                return;
            }

            Console.WriteLine($"Counter in MyTask() = {i}");
            Thread.Sleep(500);
        }
        Console.WriteLine("MyTask() finished");
    }
    static void Main(string[] args)
    {
        var cancelationTokenSource = new CancellationTokenSource();
        var task = Task.Factory.StartNew(MyTask, cancelationTokenSource.Token,
            cancelationTokenSource.Token);
        Thread.Sleep(3000);
        try
        {
            cancelationTokenSource.Cancel();
            task.Wait();
        }
        catch (Exception ex)
        {
            if(task.IsCanceled)
                Console.WriteLine("Task has been cancelled");
            Console.WriteLine(ex.Message);
        }
        finally
        {
            cancelationTokenSource.Dispose();
            task.Dispose();
        }
        Console.WriteLine("Main finished");
        Console.ReadLine();
    }
}

我正在尝试启动新任务,并在一段时间后取消它。有没有其他方法可以达到这个结果而不是使用它

if(cancellationToken.IsCancellationRequested)
        cancellationToken.ThrowIfCancellationRequested();

在 for 循环中的每次迭代中?为什么我们必须在每次迭代时检查 cancelToken.IsCancelRequest,也许我们可以使用其他东西?

取消任务的另一种方法

在这种特定情况下,您可以避免.ThrowIfCancellationRequested(),而只需使用break停止循环的执行,然后完成TaskThrowIfCancellationRequested在更深的任务树中更有用,其中有更多的后代,并且更难保持取消。

if (cancellationToken.IsCancellationRequested)
{
    break;
}

斯蒂芬·图布(Stephen Toub)很好地解释了OCE的投掷更像是一种承认。

如果任务正文也在监视取消令牌并抛出包含该令牌的OperationCanceledExceptionThrowIfCancellationRequested就是这样做的),则当任务看到该 OCE 时,它会检查 OCE 的令牌是否与任务的令牌匹配。 如果是这样,则该异常将被视为对合作取消的确认,并且任务将转换为"已取消"状态(而不是"故障"状态)。

不确定您对检查每次迭代的反对意见是什么,但如果您不想检查每次迭代,无论出于何种原因,请检查 i 的值:

例如,每 10 个循环检查一次:

if (i % 10 == 0 && cancellationToken.IsCancellationRequested)

必须检查的原因是,您可以决定在何处最好停止任务,以便工作不会处于不一致的状态。在这里,虽然你通过减少检查频率来实现的只是一个取消速度较慢的任务,但也许这会导致响应速度较慢的用户体验。 例如,任务在 500 毫秒之前结束,现在可能需要 10 倍,即 5 秒。

但是,如果每个循环

都非常快,并且每个循环检查标志证明会显着增加任务花费的总时间,那么检查每个n循环就会有意义。