先上结论:对于 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秒