一、需求
如果调用一个异步方法后,一直不给返回值结果怎么办呢?这就涉及到怎么取消任务了。
二、Task取消任务
static CancellationTokenSource source = new CancellationTokenSource();
static void Main(string[] args)
{
Task.Run(() =>
{
for (int i = 0; i < 10; i++)
{
Thread.Sleep(500);
Console.WriteLine("oh my god");
source.Token.ThrowIfCancellationRequested();
}
}, source.Token);
Thread.Sleep(2000);
Console.WriteLine("取消任务");
source.Cancel();
Console.ReadKey();
}
换一个写法
static void Main(string[] args)
{
bool isOut = false;
var task1 = Task.Run(() =>
{
for (int i = 0; i < 100; i++)
{
if (isOut) return;
Console.WriteLine("执行中" + i);
Thread.Sleep(500);
}
});
Thread.Sleep(2000);
Console.WriteLine("取消任务");
isOut = true;
Console.ReadKey();
}
我在 for 循环中加入一个判断,如果等于 true,直接跳出循环,这不也可以中断任务
三、Task取消任务的回调
取消任务也是可以加入回调的,如下:
static CancellationTokenSource source = new CancellationTokenSource();
static void Main(string[] args)
{
var task1 = Task.Run(() =>
{
for (int i = 0; i < 100; i++)
{
source.Token.ThrowIfCancellationRequested();
Console.WriteLine("执行中" + i);
Thread.Sleep(500);
}
}, source.Token);
//在指定的毫秒数后取消task执行
source.CancelAfter(2 * 1000);
//取消任务后的回调
source.Token.Register(() =>
{
//不延迟会获取不到正确的状态
Thread.Sleep(50);
Console.WriteLine("task1状态:" + task1.Status);
Console.WriteLine("IsFaulted状态:" + task1.IsFaulted);//由于未处理的异常,任务已完成。
Console.WriteLine("IsCompleted状态:" + task1.IsCompleted);//获取一个值,该值指示任务是否已完成。
});
Console.ReadKey();
}
四、Task超时处理的实现
先来一个超时取消后续代码执行的方法
private static CancellationTokenSource Cancellation = new CancellationTokenSource();
static void Main(string[] args)
{
//设置超时的时间
Cancellation.CancelAfter(TimeSpan.FromSeconds(1));
Task.Run(() =>
{
try
{
Console.WriteLine("方法执行开始");
//异步 Task.Delay 可以这么写,await Task.Delay(3000, Cancellation.Token)
//效果同 Cancellation.Token.ThrowIfCancellationRequested()
//await Task.Delay(3000, Cancellation.Token);
Thread.Sleep(2000);
Cancellation.Token.ThrowIfCancellationRequested();
Console.WriteLine("方法执行结束");
}
catch (OperationCanceledException)
{
Console.WriteLine("取消操作");
}
});
Console.ReadKey();
}
可以看到,方法执行结束这段代码并没有打印,这就是我们想要的效果了,在上面我们设置的超时时间是1秒,在后面的执行中,使用了线程睡眠时间是2秒,超时后,就自动取消操作了
把超时时间改为3秒,看看效果
private static CancellationTokenSource Cancellation = new CancellationTokenSource();
static void Main(string[] args)
{
//设置超时的时间
Cancellation.CancelAfter(TimeSpan.FromSeconds(3));
Task.Run(() =>
{
try
{
Console.WriteLine("方法执行开始");
//异步 Task.Delay 可以这么写,await Task.Delay(3000, Cancellation.Token)
//效果同 Cancellation.Token.ThrowIfCancellationRequested()
//await Task.Delay(3000, Cancellation.Token);
Thread.Sleep(2000);
Cancellation.Token.ThrowIfCancellationRequested();
Console.WriteLine("方法执行结束");
}
catch (OperationCanceledException)
{
Console.WriteLine("取消操作");
}
});
Console.ReadKey();
}
这回就没有取消任务的执行了,那么超时取消代码执行的效果就实现了。