C# Task任务详解

文章目录

  • 前言
  • Task
    • 返回值
      • 无参返回
      • 有参返回
    • async和await
      • 返回值
      • await搭配使用
      • Main async改造
    • Task进阶
      • Task线程取消
        • 测试用例
        • 超时设置
      • 线程暂停和继续
        • 测试用例
      • 多任务等最快
      • 多任务全等待
  • 结论

前言

Task是对于Thread的封装,是极其优化的设计,更加方便了我们如何操控线程

Task

Task声明形如:

public static  Task Sleep()
{

}

Task是一种类型

返回值

直接声明Task是需要返回值的。
C# Task任务详解_第1张图片

无参返回

public static  Task Sleep(int second)
{
    
    return Task.CompletedTask;
}

有参返回

 public static  Task<T> Sleep()
 {
     return Task.FromResult(T);
 }
//举例,返回参数只能唯一,除非使用元祖
 public static  Task<string> Sleep()
 {
     return Task.FromResult("Hello world!");
 }

使用Task.Result获取返回值


var res = Sleep().Result;

async和await

async和await是对于异步事件的控制,方便我们对异步事件的操控。

返回值

使用async之后可以直接设置返回值

///有参返回
 public static async  Task<string> Sleep()
 {

     return "Hello world";
 }
 ///无参返回
  public static async  Task Sleep()
 {
 }

await搭配使用

异步事件的等待使用await方法

        public static async Task Sleep(int second)
        {
            await Task.Delay(second * 1000);

            Console.WriteLine($"等待{second}s");
        }
        static void Main(string[] args)
        {
            Sleep(3);
            Sleep(2);
            Sleep(1);
            Console.WriteLine("运行完毕");
            //使用键盘键入事件阻塞主进程,主进程结束程序会立即退出
            Console.ReadKey();

        }

打印结果:
C# Task任务详解_第2张图片

打印结果显示:

  • 同步事件先结束
  • 异步事件互相不阻塞,3,2,1同时开始,等待3,2,1s打印1,2,3。

Main async改造

主程序是Void,无法等待

C# Task任务详解_第3张图片
将Void改成Task,即可等待异步事件
C# Task任务详解_第4张图片
打印结果服务预期,等待异步事件结束后运行
C# Task任务详解_第5张图片

Task进阶

C#Task取消任务执行CancellationTokenSource
C# Task 暂停与取消

Task线程取消

以前Thread有Abort()方法,强行销毁线程,但是这个方法用于极大的安全问题,已经被弃用。

C# Task任务详解_第6张图片
线程不能直接被销毁,只能通过抛出异常来取消线程。

//声明token
var tokenSource = new CancellationTokenSource();
//注册异常抛出
tokenSource.Token.ThrowIfCancellationRequested();
//注册取消事件回调
tokenSource.Token.Register(() =>
{
    Console.WriteLine("线程已被取消");
});



。。。。。。别的地方的代码
//取消token,那么之前写ThrowIfCancellationRequested的地方会直接结束
tokenSource.Cancel();

测试用例

一个简单的死循环函数,运行时返回token,用于直接跳出程序

static async Task Main(string[] args)
{

    var token = Loop();
    //等待3s抛出异常
    await Task.Delay(1000 * 3);
    Console.WriteLine("任务完成!");

    token.Cancel();
    Console.ReadKey();

}

/// 
/// 循环等待
/// 
/// 
public static CancellationTokenSource Loop()
{
    var tokenSource = new CancellationTokenSource();
    Console.WriteLine("任务开始!");
    tokenSource.Token.Register(() =>
    {
        Console.WriteLine("线程已被取消");
    });
    var count = 0;
    Task.Run(async () =>
    {
        while (true)
        {
           await Task.Delay(1000);
           //抛出异常,直接结束线程
            tokenSource.Token.ThrowIfCancellationRequested();
            count++;
            Console.WriteLine(count);
        }
    });
    return tokenSource;
}

打印结果

C# Task任务详解_第7张图片

这样使用起来也更加安全。

超时设置

tokenSource.CancelAfter是超时方法。
CancelAfter(1000):1000毫秒后超时

 static async Task Main(string[] args)
 {
     var token = Loop();
     ///3000毫秒后取消
     token.CancelAfter(1000*3);
     Console.ReadKey();

 }


 /// 
 /// 循环等待
 /// 
 /// 
 public static CancellationTokenSource Loop()
 {
     var tokenSource = new CancellationTokenSource();
     Console.WriteLine("任务开始!");
     tokenSource.Token.Register(() =>
     {
         Console.WriteLine("线程已被取消");
     });
     var count = 0;
     Task.Run(async () =>
     {
         while (true)
         {
             await Task.Delay(1000);
             tokenSource.Token.ThrowIfCancellationRequested();
             count++;
             Console.WriteLine(count);
         }
     });
     return tokenSource;
 }

线程暂停和继续

线程暂停也是使用一个类去控制,ManualResetEvent。和线程销毁一样,是不能直接暂停的,因为直接暂停也不安全。

//声明,false为默认阻塞,true为不阻塞
var resetEvent = new ManualResetEvent(false);
//暂停,通过WaitOne方法来阻塞线程,通过Set和Reset来设置是否阻塞
resetEvent.WaitOne();
//阻塞暂停
resetEvent.Set()
//取消阻塞,继续
resetEvent.Reset()

测试用例
  static async Task Main(string[] args)
  {

      var canStop = CanStop();
      //等待3s抛出异常
      Console.WriteLine("等待3s启动");
      await Task.Delay(1000 * 3);
      Console.WriteLine("启动!");
      canStop.Set();
      
      Console.WriteLine("等待3s暂停");
      await Task.Delay(3000);
      Console.WriteLine("暂停!");
      canStop.Reset();

      Console.ReadKey();

  }
   public static ManualResetEvent CanStop()
 {
     var resetEvent = new ManualResetEvent(false);
     var count = 0;
     Task.Run(async () =>
     {
         while (true)
         {
             resetEvent.WaitOne();
             await Task.Delay(1000);
             
             count++;
             Console.WriteLine(count);
         }
     });
     return resetEvent;

 }

多任务等最快

await Task.WhenAny(Task1,Task2,Task3)
只会等待最快的一个。

        static async Task Main(string[] args)
        {
            await Task.WhenAny(Sleep(1),Sleep(2),Sleep(3));
            
            Console.WriteLine("运行结束");
            Console.ReadKey();

        }

        public async static Task Sleep(int second)
        {
            await Task.Delay(second*1000);

            Console.WriteLine($"等待{second}s");
        }

运行结果

C# Task任务详解_第8张图片

多任务全等待

        static async Task Main(string[] args)
        {
            await Task.WhenAll(Sleep(1), Sleep(2), Sleep(3));

            Console.WriteLine("运行结束");
            Console.ReadKey();

        }

        public async static Task Sleep(int second)
        {
            await Task.Delay(second*1000);

            Console.WriteLine($"等待{second}s");
        }

C# Task任务详解_第9张图片

结论

异步线程的控制是极其重要的内容,Task还可以和委托一起使用,对程序的运行有更强的把控力。

你可能感兴趣的:(C#,c#,java,开发语言)