TPL异步并行编程之取消任务

TPL异步并行编程之简单使用

在上篇随笔里面说明了Task的使用,仅仅是简单使用,有时候把一个任务交给Task去执行,但是呢还是要管理下,比如说:我要叫这个任务停止了,不做了,任务取消了,或者超时了

在传统的While里面我们可以这样做,1 通过标识 2 通过一个方法抛异常,3 其他办法

举个例子:while(true){

  if(isNotCancel){

    //每次都判断下,取消没有,当然isNotCancel需要加上lock的

  }

}

难道在Task里面有什么新奇吗?其实也没啥新奇的,那Task怎么取消呢?来点干货吧

一 轮训检测

直接调用task.cancel方法,但是下Task函数体内部必须做轮训检测是否被取消,且看代码

 1 static void Main(string[] args)
 2         {
 3             CancellationTokenSource tokenSource = new CancellationTokenSource();
 4 
 5             CancellationToken token = tokenSource.Token;
 6 
 7             Task task=new Task(() =>
 8             {
 9                 while (true)
10                 {
11                     if (token.IsCancellationRequested)
12                     {
13                         break;
14                     }
15                     else
16                     {
17                         
18                     }
19                 }
20             },token);
21 
22 
23             Console.WriteLine("运行");
24 
25 
26 
27             task.Start();
28 
29             Thread.Sleep(5*1000);
30 
31             tokenSource.Cancel();
32 
33             Console.ReadKey();
34         }
View Code

二  取消过程拦截检测

在调用task.cancel方法是会在真正改变token.IsCancellationRequested值之前,调用token中所注册的函数,也就是说token.cancel(),调用后会调用token.register所注册的方法,然后再更改token.IsCancellationRequested只为true,那么反过来在注册的方法中我们就可以检测是否调用了cancel方法了也就自然检测到了已经取消了

且看代码说话:

 1 static void Main(string[] args)
 2         {
 3             CancellationTokenSource tokenSource = new CancellationTokenSource();
 4 
 5             CancellationToken token = tokenSource.Token;
 6 
 7             Task task=new Task(() =>
 8             {
 9                 while (true)
10                 {
11                     if (token.IsCancellationRequested)
12                     {
13                         break;
14                     }
15                     else
16                     {
17                         
18                     }
19                 }
20             },token);
21 
22 
23             Console.WriteLine("运行");
24 
25             token.Register(() =>
26             {
27                 Console.WriteLine("取消了,在取消之前必定调用了我");
28             });
29 
30             task.Start();
31 
32             Thread.Sleep(5*1000);
33 
34             tokenSource.Cancel();
35 
36             Console.ReadKey();
37         }
View Code

三 使用信号量来检测是否取消

现在我们启用2个Task,TaskA,TaskB,TaskB需要TaskA取消后才能执行,那么我们也可以在TaskB中执行代码时检测TaskA已被取消了,且看代码

 1 static void Main(string[] args)
 2         {
 3             CancellationTokenSource tokenSource = new CancellationTokenSource();
 4 
 5             CancellationToken token = tokenSource.Token;
 6 
 7             Task task=new Task(() =>
 8             {
 9                 while (true)
10                 {
11                     // 一直在运行,下面那个家伙得等着我被取消或者把事情做完
12                     if (token.IsCancellationRequested)
13                     {
14                         //我已被取消该时候退出了
15                         break;
16                     }
17                 }
18             },token);
19 
20 
21             Task.Run(() =>
22             {
23                 //我一开始就被上面那个task家伙挂起了,我需要他取消我才能干活~~
24                 token.WaitHandle.WaitOne();
25                 while (true)
26                 {
27                     // 开始干活
28                 }
29             });
30 
31             task.Start();
32 
33             Thread.Sleep(5*1000);
34 
35             tokenSource.Cancel();
36 
37             Console.ReadKey();
38         }
View Code

四 多个协作的Task一个取消则其他Task也被取消,这样也可以取消一组Task

就好比我们几个人一起干一件事情,但是这件事情需要每个分工的相互协作才能继续,比如玉女双休剑,需要2人同时练功才行,其中一个人说我不行了 那都不行了,且看代码

4.1 共用一个Token

 1 static void Main(string[] args)
 2         {
 3             CancellationTokenSource tokenSource = new CancellationTokenSource();
 4 
 5             // create the cancellation token
 6             CancellationToken token = tokenSource.Token;
 7 
 8             // create the tasks
 9             Task task1 = new Task(() =>
10             {
11                 for (int i = 0; i < int.MaxValue; i++)
12                 {
13                     token.ThrowIfCancellationRequested();
14                     Console.WriteLine("Task 1 - Int value {0}", i);
15                 }
16             }, token);
17 
18             Task task2 = new Task(() =>
19             {
20                 for (int i = 0; i < int.MaxValue; i++)
21                 {
22                     token.ThrowIfCancellationRequested();
23                     Console.WriteLine("Task 2 - Int value {0}", i);
24                 }
25             }, token);
26             // wait for input before we start the tasks
27             Console.WriteLine("Press enter to start tasks");
28             Console.WriteLine("Press enter again to cancel tasks");
29             Console.ReadLine();
30 
31             // start the tasks
32             task1.Start();
33             task2.Start();
34 
35             // read a line from the console.
36             Console.ReadLine();
37 
38             // cancel the task
39             Console.WriteLine("Cancelling tasks");
40             tokenSource.Cancel();
41             // wait for input before exiting
42             Console.WriteLine("Main method complete. Press enter to finish.");
43             Console.ReadLine();
44         }
View Code

4.2 Token组

 1 static void Main(string[] args)
 2         {
 3             // create the cancellation token sources
 4             CancellationTokenSource tokenSource1 = new CancellationTokenSource();
 5             CancellationTokenSource tokenSource2 = new CancellationTokenSource();
 6             CancellationTokenSource tokenSource3 = new CancellationTokenSource();
 7 
 8             // create a composite token source using multiple tokens
 9             CancellationTokenSource compositeSource =
10                 CancellationTokenSource.CreateLinkedTokenSource(
11             tokenSource1.Token, tokenSource2.Token, tokenSource3.Token);
12 
13             // create a cancellable task using the composite token
14             Task task = new Task(() =>
15             {
16                 // wait until the token has been cancelled
17                 compositeSource.Token.WaitHandle.WaitOne();
18                 // throw a cancellation exception
19                 throw new OperationCanceledException(compositeSource.Token);
20             }, compositeSource.Token);
21 
22             // start the task
23             task.Start();
24 
25             // cancel one of the original tokens
26             Thread.Sleep(2*1000);
27             tokenSource2.Cancel();
28 
29             // wait for input before exiting
30             Console.WriteLine("Main method complete. Press enter to finish.");
31             Console.ReadLine();
32         }
View Code

五 抛出异常

ThrowIfCancellationRequested,在四中已经看到如果调用cancel方法会处罚ThrowIfCancellationRequested函数的执行,那么相应的Task检测到异常如果不做任何处理的情况下也就退出了,且看代码

 1 代码
 2 
 3 Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->        static void Main(string[] args)
 4         {
 5             // create the cancellation token source
 6             CancellationTokenSource tokenSource1 = new CancellationTokenSource();
 7 
 8             // create the cancellation token
 9             CancellationToken token1 = tokenSource1.Token;
10 
11             // create the first task, which we will let run fully
12             Task task1 = new Task(() =>
13             {
14                 for (int i = 0; i < 10; i++)
15                 {
16                     token1.ThrowIfCancellationRequested();
17                     Console.WriteLine("Task 1 - Int value {0}", i);
18                 }
19             }, token1);
20 
21             // create the second cancellation token source
22             CancellationTokenSource tokenSource2 = new CancellationTokenSource();
23 
24             // create the cancellation token
25             CancellationToken token2 = tokenSource2.Token;
26 
27             // create the second task, which we will cancel
28             Task task2 = new Task(() =>
29             {
30                 for (int i = 0; i < int.MaxValue; i++)
31                 {
32                     token2.ThrowIfCancellationRequested();
33                     Console.WriteLine("Task 2 - Int value {0}", i);
34                 }
35             }, token2);
36 
37             // start all of the tasks
38             task1.Start();
39             task2.Start();
40 
41             // cancel the second token source
42             tokenSource2.Cancel();
43             // write out the cancellation detail of each task
44             Console.WriteLine("Task 1 cancelled? {0}", task1.IsCanceled);
45             Console.WriteLine("Task 2 cancelled? {0}", task2.IsCanceled);
46             // wait for input before exiting
47             Console.WriteLine("Main method complete. Press enter to finish.");
48             Console.ReadLine();
49         }
View Code

最后

其实取消Task的执行还有其他办法,也可以自己实现不一定就要TPL通过的api来实现

原文地址:https://www.cnblogs.com/rjjs/p/5584148.html