Task和异步方法

Task任务重点掌握

概念:Task是微软在.Net4.0时代推出来的,也是微软极力未推荐的一种多线程的处理方式,Task看起来像一个Thread,实际上,它是在ThreadPool的基础上进行的封装,Task的控制和扩展性很强,在线程的延续,阻塞,取消,超时等方面远胜于Thread和 ThreadPool.核心优势在于:

  • 内置任务生命周期管理(创建、运行、完成、取消等状态)
  • 支持任务延续、组合与依赖管理
  • 原生支持取消、超时和异常处理
  • 更高效的线程复用(减少线程创建销毁开销)

掌握:

1.如何实例化

2.如何启动任务

3.如何向任务中传递数据

4.任务如何管理(取消 cts.Token.IsCancellationRequested/cts.Canecl())

5.任务等待

6.任务返回值((Task<T>泛型) )

7.分线程任务中如何捕获异常(处理分线程任务中的非法情况)

重点API及类总结:

1.实例化及启动

方法特点适用场景线程池使用
new Task(() => {}).Start()手动控制启动时机,需显式调用 Start ()需要延迟执行的任务是(默认)
Task.Run(() => {})简化 API,自动启动任务大多数异步操作场景
Task.Factory.StartNew(() => {})支持丰富配置选项需要定制任务行为(如长期运行)可选(可配置)

2. 线程任务取消

类型 / 方法作用特点使用场景
CancellationTokenSource提供取消令牌的源对象可创建多个令牌,支持超时取消所有需要取消机制的任务
CancellationToken取消请求的传递载体轻量级结构,可安全传递作为参数传递给任务
cts.Cancel()立即触发取消请求同步触发取消需要立即终止任务时
cts.CancelAfter(ms)延迟指定时间后取消异步定时取消需要超时控制的任务
token.IsCancellationRequested检查是否收到取消请求非阻塞检查任务内部定期检查
token.ThrowIfCancellationRequested()若取消则抛出异常可触发异常处理流程需要通过异常处理取消的场景

3. 线程任务等待

方法作用是否阻塞返回值
task.Wait()等待单个任务完成
Task.WaitAny(tasks)等待任一任务完成完成任务的索引
Task.WaitAll(tasks)等待所有任务完成
Task.WhenAny(tasks)等待任一任务完成已完成的任务
Task.WhenAll(tasks)等待所有任务完成包含所有结果的任务
factory.ContinueWhenAny(tasks, t => {})任一任务完成后执行延续延续任务
factory.ContinueWhenAll(tasks, ts => {})所有任务完成后执行延续延续任务

4. 线程任务返回值(Task<T>泛型应用)

用法特点获取结果方式异常处理
Task<T>.Run(() => return T)异步计算并返回结果可通过 await 或 Result 获取异常包装在 AggregateException 中
await task<T>非阻塞获取结果直接获取 T 类型结果自动解包异常,可直接捕获
task<T>.Result阻塞获取结果同步获取 T 类型结果需捕获 AggregateException
task<T>.GetAwaiter().GetResult()类似 Result 但直接抛出原始异常同步获取 T 类型结果直接抛出原始异常
Task.FromResult(T)创建已完成的带结果任务立即获取预设结果无异常(除非结果本身无效)

 

Task的实例化方式

1.Task如何实例化(多种实例化方案)

  1. new Task()  
  2. Task.Run();
  3. Task 工厂

1.new Task()  默认不会自动启动  需要手动Start启动  Action和Action<T>

namespace _1.Tesk
{
    public partial class Form1 : Form
    {

        //CancellationTokenSource 主要用来像CancellationToken发一个信号,取消的信号
        //怎么发信号?cts.Token能生成唯一的标识 将来cts.Cancel()发送取消信号
        //每一个任务是一个分线程 cts.Token能生成唯一标识 将来cts.Cancel()取消任务的时候,
        知道取消哪个任务
        CancellationTokenSource cts = new CancellationTokenSource();

        public Form1()
        {
            InitializeComponent();
        }

        Task t1 = null;
        private void Form1_Load(object sender, EventArgs e)
        {
            //1.Task如何实例化(多种实例化方案)
            //1.new Task()  默认不会自动启动  需要手动Start启动  Action和Action<T>

            //public delegate void Action(); 委托
            //public Task(Action action) 构造函数
            t1 = new Task(new Action(() => { })); ;
            t1 = new Task(() => { }); ;
            t1 = new Task(DoWork); ;

            //有一个取消的标识
            t1 = new Task(DoWork, cts.Token);

            //public delegate void Action<T>(); 委托

            //t1 = new Task((obj) =>
            //{
            //    Console.WriteLine(obj);
            //});

            

1.2 Task.Run();静态方法创建任务实例 默认是自动启动  Action Func

Task.Run(new Func<string>(() => { return "Hello"; }));
Task.Run(() => { return "Hello"; });

Task.Run(new Func<int>(() => { return 123; }));
Task.Run(() => { return 123; });

Task.Run(new Func<Task>(() => { return new Task(() => { }); }));
Task.Run((() => { return new Task(() => { }); }));

Task.Run(new Func<Task<string>>(() => { return new Task<string>(() => { return "hello"; }); }));
Task.Run((() => { return new Task<string>(() => { return "hello"; }); }));

Task.Run(new Func<Task<int>>(() => { return new Task<int>(() => { return 123; }); }));
Task.Run((() => { return new Task<int>(() => { return 123; }); }));

Task.Run(new Func<Task<Task>>(() => { return new Task<Task>(() => { return new Task(() => { }); }); }));

//Task<T> 任务泛型 主要让任务能够返回结果
Task<int> tt1 = new Task<int>(() => { return 123; });
Task<string> tt2 = new Task<string>(() => { return "hello"; });

Task<Task> tt3 = new Task<Task>(() => { return new Task(() => { }); });
Task<Task<int>>tt4 = new Task<Task<int>>(() => { return new Task<int>(() => { return 1; }); });

1.3 Task 工厂

Task.Factory.StartNew(() => { });
Task.Factory.StartNew(() => { return 100; });
Task.Factory.StartNew(() => { return "hello"; });
Task.Factory.StartNew(() => { return new Task(() => { }); });

工厂方法 StartNew() 会直接创建并启动任务,简化代码。

不用实例化Task 在调用start了

asnyc和await是什么?

1. 核心原理

async/await 是基于 Task 的语法糖,允许以同步代码的形式编写异步逻辑,本质是状态机(编译器自动生成)的封装。

  • async:标记方法为异步方法,允许内部使用await
  • await:暂停当前方法执行,释放线程(不阻塞),待任务完成后恢复执行

异步编程是一种编程模式.C#中的异步线程可以通过Thread,ThreadPool,Task,async/await等来实现

多线程肯定是异步的,即多线程是异步也有可能出现在单线程的程序中.

2. 关键规则

  • async关键字是一个方法修饰符,用它声明的方法,成为异步方法.
  • await关键字用来等待一个Task或async方法完成,await关键字必须配合async关键字使用,不能单独应用await关键字.
  • await只能用在async修饰的方法(即异步方法)内使用.
  • await不会阻塞主线程.用户体验好.

3. 优势与最佳实践

优势
  • 避免回调嵌套(“回调地狱”),代码可读性接近同步逻辑
  • 非阻塞等待,提高 UI 线程响应性(如 WinForm/WPF)或服务器吞吐量(如ASP.NET
最佳实践
  • 优先返回Task/Task<T>而非void(便于等待和异常处理)
  • 异步方法命名以Async结尾(如GetDataAsync
  • 避免async void(仅用于事件处理)
  • 不要滥用Task.Result/Task.Wait()(可能导致死锁,尤其在 UI 线程)

await能等待什么?

切记:await关键字不能等待同步代码,只能等待Task或异步方法,且异步方法必须有返回值

Task 与 async/await 的关系

  • async/await是 Task 的 “语法糖”,底层仍依赖 Task 实现
  • Task 可以独立使用(如Task.Run),但async/await必须配合 Task
  • 同步方法中使用Task.Result可能导致死锁,而await可避免此问题

asnync和await实现异步方法有什么好处?

  1. 即可以保证不阻塞,也可以保证异步执行的顺序
  2. 以同步代码的方式编写异步传输,让语法更加优美.

使用:

namespace _03_asnyc和await
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            SayHello1();
            SayHello2();
            SayHello3();
        }
        private void SayHello1()
        {
            Console.WriteLine("SayHello1");
        }
        private void SayHello2()
        {
            Console.WriteLine("SayHello2");
        }
        //异步方法
        //在同步方法的前面添加一个async关键字  这个方法就会由原来的同步方法 变为异步方法
        //虽然这个方法使用了async修饰符 但是如果方法体中没有await 还是同步方法
        private async void SayHello3()
        {

            // await  等待异步执行的结果
            // await  后面等待的必须是一个任务 Task Task<T>
            Task task = new Task(() =>
            {
                Console.WriteLine("SayHello3");
            });
            task.Start();
            await task;
            await Task.Run(() =>
            {
                Console.WriteLine("另外一个任务");
            });
        }



        private void button1_Click(object sender, EventArgs e)
        {
            SayHello3();
            Console.WriteLine("后续代码后续代码");
        }

        

        private async void button2_Click(object sender, EventArgs e)
        {
            Task<int> t1=GetAsyncResult();
            await t1;
            Console.WriteLine(t1.Result+"-------");
        }



        private async Task<int> GetAsyncResult()
        {

            Task<int> t = Task.Run(() => {

                Thread.Sleep(1000);

                return 100;
            });

            int num = await t;
            Console.WriteLine(num);
            Console.WriteLine(t.Result);
            return t.Result;

        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }

        private void button3_Click(object sender, EventArgs e)
        {
            GetAsyncResult2();
        }



        //异步方法的返回值必须 为 void  或者Task 或者 Task<T>
        private async void  GetAsyncResult2()
        {
            Task<int> t = Task.Run(() => {

                Thread.Sleep(1000);

                return 100;
            });




            int num= await t;
           
            //Console.WriteLine(t.Result);
            Console.WriteLine("获取值");
        }

        private async void button4_Click(object sender, EventArgs e)
        {

            //默认情况下 任务是无序的

            //Task<string> t1 = new Task<string>(s =>
            //{
            //    Console.WriteLine("任务1");
            //    return s.ToString() + "bbbb";

            //}, "aaaa");
            //t1.Start();

            ////参数prevTask 就是上一个任务 如果t1有结果,可以通过prevTask获取,如果没有 此参数就没有用
            //Task t2 = t1.ContinueWith(prevTask =>
            //{
            //    Console.WriteLine("任务2");
            //    Console.WriteLine(prevTask.Result);

            //});

            ////参数2: 上一个任务 t2
            ////参数2: 当前任务的参数  200实参  num 形参
            //Task t3 = t2.ContinueWith((prevTask, num) =>
            //{
            //    Console.WriteLine("任务3");
            //    return (int)num;
            //}, 200);



            //Task t4 = t3.ContinueWith((prevTask) =>
            //{
            //    Console.WriteLine("任务4");
            //     Console.WriteLine(prevTask.Result);
            //});


            Console.WriteLine("------------------------");


            Task<string> t1 = new Task<string>(s =>
            {
                Console.WriteLine("任务1");
                return s.ToString() + "bbbb";

            }, "aaaa");
            t1.Start();

            await t1;

            Task t2 = Task.Run(() => {
                Console.WriteLine("任务2");
            });

            await t2;


            Task<int> t3 = new Task<int>(num =>
            {
                    Console.WriteLine("任务3");
                    return (int)num;
            },200);

            t3.Start();
            await t3;


            Task t4 = Task.Run(() => {
                Console.WriteLine("任务4");
                Console.WriteLine(t3.Result);
            });



        }
    }
}

对上面每段代码的 拆分解释 含义:

构造函数中的使用

  • SayHello1SayHello2是普通同步方法

  • SayHello3是异步方法,但在构造函数中调用时没有await,所以实际上是同步执行

同步方法展示

这个方法展示了最基本的同步执行方法,代码按顺序一行一行执行.

异步方法基础示例

这里展示了:

1.手动创建和启动Task

2.使用await等待任务完成

3.使用Task.Run简化任务创建

按钮点击事件中的异步调用

这里演示了不等待异步方法完成的后果:"后续代码"会立即执行,而不会等待SayHello3完成。

带返回值的异步方法

这段代码展示了:

  1. 如何定义返回值的异步方法(Task<T>)

  2. 两种获取结果的方式:await.Result

  3. 在UI事件处理中使用async void的合理场景

任务延续(Continuation)示例

这段代码展示了:

  1. 使用await实现顺序异步操作

  2. 每个任务完成后才执行下一个

  3. 可以访问前序任务的结果

扩展:

线程池、Task任务、async异步方法 C#多线程深入解析与实战-CSDN博客 C#中的多线程和异步编程详解 - Jack-sparrow - 博客园 https://www.toutiao.com/article/7137485547618288169 https://www.toutiao.com/article/7255526505097347599 C#Task详解_C#Task用法介绍-C#.Net教程-PHP中文网

Task任务: C# Task详解 - 五维思考 - 博客园 C# Task详解 - 漫思 - 博客园 C# Task任务详细讲解-CSDN博客 C# Task详解 - yinjun98 - 博客园

async和await: 深入解析C#中的async和await关键字_C#教程_脚本之家 使用 Async 和 Await 的任务异步编程 (TAP) 模型 - C# | Microsoft Learn https://devblogs.microsoft.com/dotnet-ch/async-await在-c语言中是如何工作的/

异步编程模型变迁: 谈谈c#中异步编程模型的变迁_c# 异步编程模型进化-CSDN博客 C# 实现异步编程的几种方式_c# 异步方法-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值