• 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来实现

  • 相关阅读:
    MongoDB Schema Design
    WinDBG中的poi是做什么用的?
    如何在Visual Studio中运行和调试汇编代码?
    [翻译图书] 未完工 Moving Applications to the Cloud on the Microsoft Windows Azure Platform 4
    在Word中生成随机的样本文本
    Quiz Win32内存表示与数值大小
    rep stos dword ptr es:[edi] 是做什么的?
    Windows Azure中虚拟机无法启动, 报错RoleStateUnknown的解决方案
    COM基础介绍
    64位的dump里如何寻找第一个到第四个参数?
  • 原文地址:https://www.cnblogs.com/rjjs/p/5584148.html
Copyright © 2020-2023  润新知