C# 在时间延迟后完成的可取消任务 Task.Delay(int millisecondsDelay, CancellationToken cancellationToken)

先上结论:对于 Task.Delay() 的取消,需要去处理异常 TaskCanceledException ,否则会将整个Task取消。

功能:程序需要定时执行数据库数据查询,并在某些配置参数修改后,立即刷新数据:

执行以下代码,Cancellation.Cancel() 后不会有 "t1 完成等待" 出现,说明程序并没有按照设想的方式执行。

        static CancellationTokenSource Cancellation = new CancellationTokenSource();
        static void Main(string[] args)
        {

            Task t1 = MainTask();//主任务
            Thread.Sleep(1000);
            Cancellation.Cancel();//取消t1中的等待,立即执行任务主内容
            Console.ReadKey();
        }

        private static Task MainTask()
        {
            var t1 = Task.Run(async () =>
            {
                //定时操作
                while (true)
                {
                    Print("t1 执行某些任务");
                    Print("t1 开始等待10秒");
                    await Task.Delay(10000, Cancellation.Token);//等待指定时长,指定可取消任务,是为了在任务外可立即跳过等待去刷新数据
                    Print("t1 完成等待");
                }
            });
            return t1;
        }

        static void Print(string msg)
        {
            Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}: {msg}");
        }

因此加了一个任务(在函数TaskMonitor中)去监控主任务 t1 的状态如下:

        static CancellationTokenSource Cancellation = new CancellationTokenSource();
        static void Main(string[] args)
        {

            Task t1 = MainTask();//主任务
            TaskMonitor(t1);//监控任务
            Thread.Sleep(1000);
            Cancellation.Cancel();//取消t1中的等待,立即执行任务主内容
            Console.ReadKey();
        }

        private static Task MainTask()
        {
            var t1 = Task.Run(async () =>
            {
                //定时操作
                while (true)
                {
                    Print("t1 执行某些任务");
                    Print("t1 开始等待10秒");
                    await Task.Delay(10000, Cancellation.Token);//等待指定时长,指定可取消任务,是为了在任务外可立即跳过等待去刷新数据
                    Print("t1 完成等待");
                }
            });
            return t1;
        }

        private static void TaskMonitor(Task t1)
        {
            //监控主任务状态,正式程序中不需要此任务
            Task.Run(async () =>
            {
                var taskStatus = TaskStatus.Running;
                var cancellationStatus = false;
                while (true)
                {
                    if (taskStatus != t1.Status)
                    {
                        taskStatus = t1.Status;
                        Print($"t1 状态:{taskStatus}");
                    }
                    if (cancellationStatus != Cancellation.IsCancellationRequested)
                    {
                        cancellationStatus = Cancellation.IsCancellationRequested;
                        Print($"t1 中的等待取消请求状态:{Cancellation.IsCancellationRequested}");
                    }
                    await Task.Delay(10);
                }
            });
        }

        static void Print(string msg)
        {
            Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}: {msg}");
        }

运行结果如下,t1被取消了:

[2021-09-14 08:39:43.763] t1 状态:WaitingForActivation
[2021-09-14 08:39:43.763] t1 执行某些任务
[2021-09-14 08:39:43.771] t1 开始等待10秒
[2021-09-14 08:39:44.785] t1 中的等待取消请求状态:True
[2021-09-14 08:39:44.813] t1 状态:Canceled

将 t1 中的Task.Delay() 加上错误处理Try {}catch(TaskCanceledException){} 后如下:

        static CancellationTokenSource Cancellation = new CancellationTokenSource();
        static void Main(string[] args)
        {

            Task t1 = MainTask();//主任务
            TaskMonitor(t1);//监控任务
            Thread.Sleep(1000);
            Cancellation.Cancel();//取消t1中的等待,立即执行任务主内容
            Console.ReadKey();
        }

        private static Task MainTask()
        {
            var t1 = Task.Run(async () =>
            {
                //定时操作
                while (true)
                {
                    Print("t1 执行某些任务");
                    Print("t1 开始等待10秒");
                    try
                    {
                        await Task.Delay(10000, Cancellation.Token);//等待指定时长,指定可取消任务,是为了在任务外可立即跳过等待去刷新数据
                    }
                    catch(TaskCanceledException)
                    {
                        Cancellation.Dispose();
                        Cancellation = new CancellationTokenSource();
                    }
                    Print("t1 完成等待");
                }
            });
            return t1;
        }

        private static void TaskMonitor(Task t1)
        {
            //监控主任务状态,正式程序中不需要此任务
            Task.Run(async () =>
            {
                var taskStatus = TaskStatus.Running;
                var cancellationStatus = false;
                while (true)
                {
                    if (taskStatus != t1.Status)
                    {
                        taskStatus = t1.Status;
                        Print($"t1 状态:{taskStatus}");
                    }
                    if (cancellationStatus != Cancellation.IsCancellationRequested)
                    {
                        cancellationStatus = Cancellation.IsCancellationRequested;
                        Print($"t1 中的等待取消请求状态:{Cancellation.IsCancellationRequested}");
                    }
                    await Task.Delay(10);
                }
            });
        }

        static void Print(string msg)
        {
            Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}: {msg}");
        }

执行结果正常,第一次和第二次间隔1s,第二次和第三次间隔10s:

[2021-09-14 08:50:21.910] t1 状态:WaitingForActivation
[2021-09-14 08:50:21.910] t1 执行某些任务
[2021-09-14 08:50:21.919] t1 开始等待10秒
[2021-09-14 08:50:22.900] t1 中的等待取消请求状态:True
[2021-09-14 08:50:22.974] t1 完成等待
[2021-09-14 08:50:22.974] t1 执行某些任务
[2021-09-14 08:50:22.976] t1 开始等待10秒
[2021-09-14 08:50:22.985] t1 中的等待取消请求状态:False
[2021-09-14 08:50:32.977] t1 完成等待
[2021-09-14 08:50:32.977] t1 执行某些任务
[2021-09-14 08:50:32.978] t1 开始等待10秒

你可能感兴趣的:(c#)