假设有一个类似如下的过程:
private static void Print(int max)
{
for(var i = 0; i < max; i++)
{
Thread.Sleep(1000);
Console.WriteLine($"当前:{i}");
}
}
//创建Task
var task = Task.Factory.StartNew(() => Print(100));
这里,新增了一个task,每隔1秒在控制台输出一段数据,直到循环结束。如果希望在task执行过程中,可以取消task,可以使用CancellationToken,对代码进行改造,如下:
private static void Print(CancellationToken token, int max)
{
for(var i = 0; i < max; i++)
{
token.ThrowIfCancellationRequested();
Thread.Sleep(1000);
Console.WriteLine($"当前:{i}");
}
}
//创建task
CancellationTokenSource tokenSource = new CancellationTokenSource();
var task = Task.Factory.StartNew(() => Print(tokenSource.Token, 100));
//其它操作
//取消任务
tokenSource.Cancel();
这里,自定义方法中接收一个CancellationToken参数,并调用ThrowIfCancellationRequested()在取消后,中止Task的执行。由于这个是主动检查,所以在调用了Cancel()后,Task并不会立即中止。
如果细心一点,会发现StartNew有一系列方法签名包括了CancellationToken参数的方法,例如:StartNew(Action action, CancellationToken cancellationToken),是否可以使用它直接取消task而不用对现有方法进行改造呢。把上面的方法调整为如下:
private static void Print(int max)
{
for(var i = 0; i < max; i++)
{
Thread.Sleep(1000);
Console.WriteLine($"当前:{i}");
}
}
//创建task
CancellationTokenSource tokenSource = new CancellationTokenSource();
var task = Task.Factory.StartNew(() => Print(100), tokenSource.Token);
//其它操作
//取消任务
tokenSource.Cancel();
运行后,发现在tokenSource.Cancel()后,task还在继续执行。如果把代码改造成下,就可以了解StartNew方法的CancellationToken参数的作用了:
private static void Print(int max)
{
for(var i = 0; i < max; i++)
{
Thread.Sleep(1000);
Console.WriteLine($"当前:{i}");
}
}
//创建task
CancellationTokenSource tokenSource = new CancellationTokenSource();
//启动前就取消
tokenSource.Cancel();
var task = Task.Factory.StartNew(() => Print(100), tokenSource.Token);
测试会发现,task并没有启动,因此可以确定,StartNew方法的CancellationToken会决定task是否启动,而想实现task中途取消,则需要自定义方法中使用token.ThrowIfCancellationRequested();才可以。