C# 任务(Task)的基础实现

目录


一、基本概念

  • 在 C# 中,Task(任务) 属于 System.Threading.Tasks 命名空间中。自 .NET 4.0 引入以来,已成为 C# 异步和并行编程的核心基础功能。
  • Task 就是一个 "待执行的工作单元",由 线程池(ThreadPool) 管理,所以实质上也是线程处理,与主线程不冲突。因为不用手动创建 / 销毁线程,更轻量、更高效、更易管理。
  • 任务的两种核心用途,即:1. 后台执行任务(多线程)不阻塞主线程,让代码在后台运行;2. 异步操作(I/O 操作)文件读写、网络请求、数据库查询等,不占用 CPU主线程。

二、Task 的基础实现

1、最简单基础的表达

  • Task.Run(() =>{...});是最Task任务最精简表达,参看下面的代码实例。
  • 注意System.Threading.Task记得加上,否则每次在调用时代码时写全。
  • => 后的大括号内可以直接执行任务也可以封装函数来运行。
c 复制代码
using System;
using System.Threading.Tasks;
void MyTask()
{ 
       Console.WriteLine("任务开始");
       // 启动一个后台任务
       Task.Run(() =>
       {
           Console.WriteLine("任务开始执行");
           // 模拟耗时操作
           Task.Delay(2000).Wait(); 
           Console.WriteLine("任务执行完成");
       });

       Console.WriteLine("主线程继续执行"); 
}

2、带返回参数的表达

  • 可以看到下面代码中,定义了 Task 的类型为整形int作为返回值,因为我们调用的函数Sum()返回值就是int。
  • 这里用了比较标准的写法,也就是Task.Run + async/await的写法,async和await必须是同时出现的。
  • 等待任务完成并获取结果的"int result = task.Result;"这句话非常关键,没有这句话就不会等待2秒后的任务完成获取返回值,程序则会继续运行,result将得不到计算结果,result将输出结果为0。
c 复制代码
//调用
private void MyTask()
{ 
   	Console.WriteLine("任务开始");
   	int a=1;int b=2;int result =0;
   	// 任务返回 int 类型结果
   	Task<int> task = Task.Run(() =>  Sum(a,b)); 
   	// 等待任务完成并获取结果//关键
   	result = task.Result; 
   	Console.WriteLine("结果:" + result); // 输出 3
}

//任务
private async int Sum(int A,int B)
{
   //模拟任务时间2秒
   await Task.Delay(2000);
   //返回值
   return (A+B); 
}

10:33:54:608 任务开始

10:33:56:613 任务内结果:3

10:33:56:613 结果:3

3、无返回值等待任务结束

  • 如果没返回值,一般情况是继续往下执行,以达到多线程异步处理,也就是不等待任务完成父线程继续往下执行,如果我们一样是需要等待呢?那,那,那也是可以实现的( ̄▽ ̄) ,运行任务后没有返回值等待,那我们就等待整个任务,await task等待任务运行结束。需要注意的是必须用async修饰定义该函数。
  • 可以看到到输出运行结果同前面的输出结果是一样的,我们换成了全局变量(R)来接收结果。
csharp 复制代码
//全局变量 
int R = 0;
//调用
private async void MyTask()
{ 
    Console.WriteLine("任务开始");
    int a = 1; int b = 2; 
    // 任务返回 int 类型结果,不获取返回值
    Task task = Task.Run(() => Sum(a, b));
    await task;//等待运行结束 
   //等待任务完成后打印
   Console.WriteLine("结果:" + R); // 输出 3
}

//任务
private async Task<int> Sum(int A, int B)
{          
    //模拟任务时间2秒
    await Task.Delay(2000);  
     R = A+B;
      // 输出结果
    Console.WriteLine("任务内结果:" + R);
    return R;
}

输出

10:31:31:103 任务开始

10:31:33:092 任务内结果:3

10:31:33:092 结果:3

4、停止业务

  • 需要控制任务的停止,可以新建一个取消令牌源,可以叫它取消开关或标志。
  • 在调用任务前我可以定义一个毫秒时间来控制器停止,实例中给了1秒(1000),通过输出内容我们可以看到其停止的效果,和线程中停止线程循环的效果基本一样。
csharp 复制代码
//新建取消令牌源
CancellationTokenSource cts = new CancellationTokenSource();
//调用
private async void MyTask()
{ 
	int a = 1; int b = 2;
	// 1秒后取消任务
	cts.CancelAfter(1000); 
	Console.WriteLine("任务开始");
	// 任务返回 int 类型结果
	Task<int> task = Task.Run(() => Sum(a, b),cts.Token);
	//等待并读取结果
	int result = task.Result;
	//输出打印任务结果
	Console.WriteLine("结果:" + result); 
}

//任务
private async Task<int> Sum(int A, int B)
{
    int R = 0;
    //查看标志循环
    while (!cts.Token.IsCancellationRequested)
    {
        //模拟循环
        await Task.Delay(100);
        R += A + B;
        Console.WriteLine("任务内结果:" + R);
    }               
     
    return R;
}

输出

10:20:52:514 任务开始

10:20:52:777 任务内结果:3

10:20:52:777 任务内结果:6

10:20:53:025 任务内结果:9

10:20:53:025 任务内结果:12

10:20:53:265 任务内结果:15

10:20:53:265 任务内结果:18

10:20:53:265 任务内结果:21

10:20:53:522 任务内结果:24

10:20:53:522 任务内结果:27

10:20:53:522 结果:27

4、其他功能和状态

  • 其它功能和状态获取简单介绍一下。

(1) 等待任务

csharp 复制代码
task.Wait();          // 等待单个任务
Task.WaitAll(t1, t2); // 等待所有任务完成
Task.WaitAny(t1, t2); // 等待任意一个完成

(2)获取状态

csharp 复制代码
task.IsCompleted      // 是否完成
task.IsFaulted        // 是否出错
task.IsCanceled       // 是否取消
task.Status           // 详细状态

三、总结

  • C#中的Task任务是个高级的多线程异步操作方案,优先用 Task.Run + async/await的格式来描述;
  • 注意await task和task.Wait()是有区别的,await task不阻塞线程,异步等待,线程可以去干别的,而task.Wait()阻塞线程,死等,线程卡死在这里不动。
  • 任务对比Thread线程 更轻量、高效、易维护,还支持返回值、等待、取消等等操作,这么高级的任务功能,大家可以用起来哟!
相关推荐
烛阴5 小时前
Unity资源加载进化论:从AssetBundle到Addressables,一文带你吃透手游资源管理
前端·c#·unity3d
aini_lovee7 小时前
C#与倍福PLC(通过ADS协议)通信上位机源程序实现
开发语言·c#
2501_930707788 小时前
使用C#代码压平 PDF 表单字段
数据库·pdf·c#
IT知识分享11 小时前
数字上标、下标如何打,6种常用方法详解
开发语言·c#·xhtml
码农学院12 小时前
itextsharp .net中如何设置两个表格的间距设为0,取网站的域名,协议、端口、当前站点目录的地址
开发语言·c#·.net
monkeyhlj13 小时前
Agent Skills简单理解
开发语言·c#
星河耀银海13 小时前
Unity C#入门:变量的定义与访问权限(public/private)
unity·c#·lucene
asdzx6714 小时前
使用 C# 添加或读取 Excel 公式:完整指南
开发语言·c#·excel
加号314 小时前
【C#】 中 BCD 字节数组转十进制字符串的原理与实现思路
开发语言·c#