根据微软官方文档,推荐用TAP模式编写异步程序,提供了用于取消Task的 CancellationToken 标记,实际应用中可以new 一个CancellationTokenSource对象。当我们需要一个循环执行的机制时(在Thread方式下通常是用Thread.Sleep,在Task下就是await Task.Delay),需要停下来时,由于线程或Task从外部都是无法停止的,要在内部通过这个 CancellationToken 来自行停下来, 那么就有两个选择:
- 每次循环开始时,使用 cancellationToken.IsCancellationRequested 判断要不要停下来;
- 在Task.Delay里面加上cancellationToken参数,然后截获Task.Delay抛出的 OperationCanceledException 异常。
以Delay 50ms为例,测试结果表明,Cancel前等待时间 方法1要短于方法2,估计方法2的 throw-try-catch 代价比较高,推荐使用方法1。
方法1,只通过 IsCancellationRequested 测试:
static void Main(string[] args)
{
System.Threading.CancellationTokenSource quitFlag = new System.Threading.CancellationTokenSource();
testCancel1(quitFlag.Token);
Task.Delay(250).Wait();
Console.WriteLine(DateTime.Now.ToString("HH:mm:ss fff") + " Cancel...");
quitFlag.Cancel();
Console.Read();
}
static async void testCancel1(System.Threading.CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
Console.WriteLine(DateTime.Now.ToString("HH:mm:ss fff"));
await Task.Delay(50);
}
Console.WriteLine(DateTime.Now.ToString("HH:mm:ss fff") + " Cancelled");
}
//09:50:18 286
//09:50:18 413
//09:50:18 474
//09:50:18 527
//09:50:18 587
//09:50:18 603 Cancel...
//09:50:18 649 Cancelled
方法2,通过 IsCancellationRequested 和 Delay(50,cancellationToken) 截获异常:
static void Main(string[] args)
{
System.Threading.CancellationTokenSource quitFlag = new System.Threading.CancellationTokenSource();
testCancel1(quitFlag.Token);
Task.Delay(250).Wait();
Console.WriteLine(DateTime.Now.ToString("HH:mm:ss fff") + " Cancel...");
quitFlag.Cancel();
Console.Read();
}
static async void testCancel2(System.Threading.CancellationToken cancellationToken)
{
try
{
while (!cancellationToken.IsCancellationRequested)
{
Console.WriteLine(DateTime.Now.ToString("HH:mm:ss fff"));
await Task.Delay(50, cancellationToken);
}
Console.WriteLine(DateTime.Now.ToString("HH:mm:ss fff") + " Cancelled");
}
catch(OperationCanceledException ex)
{
Console.WriteLine(DateTime.Now.ToString("HH:mm:ss fff") + " Throwed");
}
}
//09:53:50 718
//09:53:50 843
//09:53:50 900
//09:53:50 964
//09:53:51 029
//09:53:51 031 Cancel...
//09:53:51 808 Throwed