取消任务-CancellationToken

1.创建CancellationToken

1.1由用户创建的CancellationTokenSource获取(推荐

每一个CancellationTokenSource都有自己的CancellationToken,CancellationTokenSource的作用是发出取消请求,被发出请求的代码持有。CancellationToken的作用是响应取消请求,被可以被停止的代码持有。

CancellationTokenSource tokenSource = new CancellationTokenSource();
CancellationToken token=tokenSource.Token;

 1.2CancellationToken构造函数或者CancellationToken.None创建

这样创建出来的CancellationToken在创建之初就处于未取消或已取消状态,并将一直保持此状态无法改变,在少数情况下会用到。

CancellationToken token = new CancellationToken();

CancellationToken token = CancellationToken.None;

 

2.几种取消方式

2.1超时取消

获取若干次网站内容,超过一定时间取消任务。

static async Task Main(string[] args)
{
    //方式1
    CancellationTokenSource tokenSource = new CancellationTokenSource(3000);
    /*方式2
    CancellationTokenSource tokenSource = new CancellationTokenSource();
    tokenSource.CancelAfter(3000);
    */
    CancellationToken token = tokenSource.Token;
    Console.WriteLine(DateTime.Now);
    await DownloadAsync("https://www.youzack.com", 100, token);
}

static async Task DownloadAsync(string url, int count, CancellationToken token)
{
    using (HttpClient c = new HttpClient())
    {
        for (int i = 0; i < count; i++)
        {
            string html = await c.GetStringAsync(url);
            Console.WriteLine(DateTime.Now);
            //方式一,检测到取消请求,抛出异常
            token.ThrowIfCancellationRequested();
            /*方式二,属性判断token是否处于取消状态,跳出循环
            if(token.IsCancellationRequested)
            {
                Console.WriteLine("请求取消!");
                break;
            }
            */
        }
    }
}

ThrowIfCancellationRequested方式的执行结果:IsCancellationRequested方式的执行结果:

2.1 某些API的异步方法中直接传递CancellationToken

api内部处理取消请求,可能机制更完善,比我们自己判断来处理的更及时。当一个请求耗时时长超过了设定的超时取消时长,就会出现取消不及时的情况。

static async Task DownloadAsync(string url, int count, CancellationToken token)
{
    using (HttpClient client = new HttpClient())
    {
        for (int i = 0; i < count; i++)
        {
            HttpResponseMessage response = await client.GetAsync(url, token);
            if (!response.IsSuccessStatusCode)
                throw new Exception("Failed to get web data.");
            string result = await response.Content.ReadAsStringAsync();
            Console.WriteLine(DateTime.Now);
        }
    }
}

2.3 手动取消

 static async Task Main(string[] args)
 {
     CancellationTokenSource tokenSource = new CancellationTokenSource();
     CancellationToken token = tokenSource.Token;
     DownloadAsync("https://www.youzack.com", 100, token);
     while(Console.ReadLine()!="q")
     { }
     tokenSource.Cancel();
     Console.ReadLine();
 }

2.4取消的回调方法

CancellationTokenSource Source = new CancellationTokenSource();
Source.Token.Register(() =>
{
    Console.WriteLine("当前的Source已经被取消");
});
Task T = Task.Factory.StartNew(() =>
{
    while (!Source.IsCancellationRequested)
    {
        Thread.Sleep(100);
        Console.WriteLine("当前Thread正在运行{0}", Thread.CurrentThread.ManagedThreadId);
    }
}, Source.Token);
Thread.Sleep(1000);
Source.Cancel();

2.5组合取消

//只要一个被取消,comineSource的组合就被取消,类似于WhenAny
CancellationTokenSource Source = new CancellationTokenSource();
Source.Cancel();
CancellationTokenSource Source2 = new CancellationTokenSource();
//comineSource 里面只要有一个被取消了,comineSource的状态就被取消
var comineSource = CancellationTokenSource.CreateLinkedTokenSource(Source.Token, Source2.Token);             
Console.WriteLine("s1={0},s2={1},s3={2}", Source.IsCancellationRequested, Source2.IsCancellationRequested, comineSource.IsCancellationRequested);

2.6总结

cts.Cancel():只是设置一个状态,也就是设置cts.IsCancellationRequested为ture。

cts.Token.ThrowIfCancellationRequested():检查cts.IsCancellationRequested是否为true,如果为 true就抛出一个异常,从而终止线程的执行。

和以下代码同理:

if (token.IsCancellationRequested)
{
    new OperationCanceledException();
}

 

3..Net Core MVC 框架提供的CancellationToken

 //提供CancellationToken的重载
 public async Task<IActionResult> Index(CancellationToken token)
 {
     await DownloadAsync("https://www.youzack.com", 100, token);
     return View();
 }

 static async Task DownloadAsync(string url, int count, CancellationToken token)
 {
     using (HttpClient client = new HttpClient())
     {
         for (int i = 0; i < count; i++)
         {
             HttpResponseMessage response = await client.GetAsync(url, token); ;
             string result = await response.Content.ReadAsStringAsync(); ;
             Debug.WriteLine(DateTime.Now);
         }
     }
 }

跳转到其他网页可取消请求:

posted @ 2023-12-20 23:56  茜茜87  阅读(4)  评论(0编辑  收藏  举报