C#——多线程之Task

news2024/11/26 5:35:20

C#——多线程之Task

  • 前言
  • 一、Task是什么?
  • 二、各应用场景以及实例分析
    • 1.异步执行代码
    • 2.等待异步操作完成
    • 3.并行执行多个任务
    • 4.处理异常
    • 5.取消异步操作
  • 三、一些其他问题
    • 1.WhenAll与WhenAny的区别
  • 总结


前言

在代码编写过程中,经常会用到多线程的知识,实现方法有很多种,突然想总结并理清楚其中的相关性与差异性。故以此开篇总结各种工具的用法与注意事项。本篇将对Task稍作总结。


一、Task是什么?

Task 是 .NET 中用于表示异步操作的类,它提供了一种简单和强大的方式来处理异步编程。Task 可以用于各种应用场景和功能,包括:

  1. 异步执行代码:Task 允许在单独的线程上执行代码块,从而避免阻塞主线程,提高程序的响应性和并发性。
  2. 等待异步操作完成:通过 await 关键字可以等待 Task 完成,从而实现非阻塞的异步操作。
  3. 并行执行多个任务:Task 可以用于并行执行多个独立的任务,从而加快任务的完成速度,提高系统的性能。
  4. 处理异常:Task 提供了异常处理机制,可以在异步操作中捕获和处理异常。
  5. 轻量级的线程管理:Task 使用线程池来管理线程,避免了频繁创建和销毁线程的开销,使得线程的管理更加高效。
  6. 取消异步操作:Task 支持取消操作,可以通过 CancellationToken 来取消正在进行的异步操作。

总的来说,Task 是一种非常有用的工具,它在异步编程中起着至关重要的作用,可以帮助开发人员编写高效、响应式和可靠的异步代码。

二、各应用场景以及实例分析

1.异步执行代码

假设我们需要在后台线程中执行一个耗时的操作,而不阻塞主线程。使用 Task 可以很方便地实现这一点。例如,我们可以使用 Task.Run 方法在后台线程中执行一个计算操作,然后在主线程中继续执行其他代码:

代码如下(示例):

        static void Main(string[] args)
        {
            Task.Run(() =>
            {
                Console.WriteLine("task");
                Task.Delay(2000).Wait(); //模拟耗时操作
                Console.WriteLine("taskEnd");
            });
            Task.Delay(1000).Wait();
            Console.WriteLine($"main");
            Console.ReadKey();
        }

结果如下图:
在这里插入图片描述

2.等待异步操作完成

使用 await 关键字可以等待 Task 完成,从而实现非阻塞的异步操作。例如,在 Windows Forms 或 WPF 应用程序中,我们可以在异步方法中使用 await 来等待异步操作完成后更新 UI:

        public static async Task wait()
        {
            await Task.Delay(2000); //将等待2秒后,继续执行下面的代码
            Console.WriteLine("Wait 2000 ms");
        }

3.并行执行多个任务

假设我们有多个独立的任务,可以使用 Task.WhenAll 方法来等待它们执行完成。
代码如下(示例):

        static async Task test()
        {
            Task[] tasks = new Task[3];
            tasks[0] = wait();
            tasks[1] = wait2();
            tasks[2] = wait3();

            await Task.WhenAll(tasks);

            Console.WriteLine("main");
            Console.ReadKey();

        }
        public static async Task wait()
        {
            await Task.Delay(2000);
            Console.WriteLine("Wait 2000 ms");
        }
        public static async Task wait2()
        {
            await Task.Delay(3000);
            Console.WriteLine("Wait 3000 ms");
        }
        public static async Task wait3()
        {
            await Task.Delay(4000);
            Console.WriteLine("Wait 4000 ms");
        }

结果如下图:
在这里插入图片描述

ps:
上述代码有个小细节:在 test() 方法中,没有显式地调用 Start() 方法,因为在使用 async/await 时不需要手动启动任务。async 方法本身会确保异步方法在调用时会自动启动,所以不需要手动调用 Start()。

遇到点小问题:
我在通过入下代码,new task进行新建,start进行启动时,出现Main在wait 。。前先被打印出来如下:

        static async Task test()
        {
            Task[] tasks = new Task[3]
            {
               new Task( ()=>  wait()),
               new Task( ()=>  wait2()),
               new Task( ()=>  wait3())
            };
            foreach (var item in tasks)
            {
                item.Start();
            }
            await Task.WhenAll(tasks);
            Console.WriteLine("main");
            Console.ReadKey();
        }

在这里插入图片描述

Task.WhenAll() 方法只能等待当前线程池中的任务完成。如果任务没有被调度到线程池上运行,那么 Task.WhenAll() 方法将无法等待这些任务完成。
当你使用 Task.Run() 或 Task.Factory.StartNew() 方法创建任务时,这些任务会被自动调度到线程池上运行,因此 Task.WhenAll() 方法可以等待它们的完成。
而通过 new Task() 创建任务对象后,手动调用 Start() 方法来启动任务,但这些任务并没有被自动调度到线程池上运行。因此,Task.WhenAll() 方法无法等待这些任务完成。

4.处理异常

Task 提供了异常处理机制,可以在异步操作中捕获和处理异常。例如,我们可以使用 try-catch 块来处理异步操作中可能抛出的异常:

        static void Main(string[] args)
        {
            test();
            Console.WriteLine("main");
            Console.ReadKey();
        }

        static async void test()
        {
            try
            {
                await wait();
            }
            catch (Exception)
            {
                Console.WriteLine("报错啦!");
            }
        }


        public static async Task wait()
        {
            await Task.Delay(2000);
            Console.WriteLine("Wait 2000 ms");
            throw new Exception("wwww");
        }

结果如下:
在这里插入图片描述

ps:此处需要注意的是try/catch在await上下文时才能生效,否则无法捕获到异常。

5.取消异步操作

Task 支持取消操作,可以通过 CancellationToken 来取消正在进行的异步操作。例如,我们可以在异步方法中检查 CancellationToken 的状态,并在需要时取消操作:

        static void Main(string[] args)
        {

            CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
            CancellationToken cancellationToken = cancellationTokenSource.Token;

            Task.Run(async () =>
            {
                try
                {
                    int i = 0;
                    while (!cancellationToken.IsCancellationRequested)
                    {
                        await Task.Delay(1000);
                        Console.WriteLine($"第{i}次等待");
                        i += 1;
                    }
                    cancellationToken.ThrowIfCancellationRequested();//可弹出OperationCanceledException类型的错误
                }
                catch (OperationCanceledException)
                {
                    Console.WriteLine($"任务被取消");
                }
            }, cancellationToken);

            Thread.Sleep(5000);
            cancellationTokenSource.Cancel();//取消任务

            Console.ReadKey();
        }

结果如下图:
在这里插入图片描述

ps:其实通过一个全局布尔变量也可以达到上面中止任务的效果,但cancellationToken中封装了一些取消任务后的回调,减少了自己码代码的时间,但增加了学习理解的成本。

三、一些其他问题

1.WhenAll与WhenAny的区别

WhenAll:是要等待所以的任务完成才返回;如上文并行任务章节内容。
WhenAny:只要一个任务完成,就立马结束等待。如下。

        static async Task test()
        {
            Task[] tasks = new Task[3];
            tasks[0] = wait();
            tasks[1] = wait2();
            tasks[2] = wait3();
            
            await Task.WhenAny(tasks);
            Console.WriteLine("main");
            Console.ReadKey();
        }

在这里插入图片描述


总结

上文我们通过各实例内容,粗略了解了Task的各种应用,在使用中还会遇见多种问题,在此无法详尽的列举出来。在以后的过程中,如果遇见问题的话我会陆续更新到这里,希望本文对大家有所帮助。下次我们将继续了解多线程中的Thread。我们下次再见。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/794365.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vue如何配置eslint

eslint官网: eslint.bootcss.com eslicate如何配置 1、选择新的配置: 2、选择三个必选项 3、再选择Css预处理器 4、之后选择处理器 5、选择是提交的时候就进行保存模式 6、放到独立的配置文件上去 7、最后一句是将自己的数据存为预设 8、配合console不要出现的规则…

每天一道C语言编程(2^k进制数)

题目描述 设r是个2^k 进制数,并满足以下条件: (1)r至少是个2位的2^k 进制数。 (2)作为2^k 进制数,除最后一位外,r的每一位严格小于它右边相邻的那一位。 (3)…

NoSQL之 Redis 部署,配置与优化

文章目录 NoSQL之 Redis配置与优化一.关系数据库与非关系型数据库1.关系型数据库2.非关系型数据库3.关系型数据库和非关系型数据库区别4.非关系型数据库产生背景 二.Redis简介1.了解Redis2.Redis 具有以下几个优点3.Redis为何这么快 三.Redis 安装及应用1.Redis 安装部署2.Redi…

linux网卡命名规则与修改方法

一.前言: 在早期的的操作系统中例如fedora13或者ubuntu15之前网卡命名的方式为eth0,eth1,eth2,属于biosdevname 命名规范。当然这是针对intel网卡的命名规则,对于realtek类型的网卡会命名为ens33。但是这个编号往往不一…

数据库运维——MySQL主从复制

1.理解MySQL主从复制原理。 2.完成MySQL主从复制。 一、MySQL主从复制原理 MySQL主从复制是指将一个MySQL数据库服务器(称为主服务器)上的数据复制到其他MySQL数据库服务器(称为从服务器)的过程。它的原理如下: 主服…

如何利用OpenAI的函数调用特性

如何利用OpenAI的函数调用特性 函数调用能实现哪些功能? 简单来说,函数调用功能可以助你在请求方法时构建结构化的数据。因为生成模型的特性,它产生的数据往往是无结构的,即使在提示(prompt)中指定了输出格式,但实际…

3-Linux实操

Linux实践操作 开关机、重启、用户登陆注销关机&重启用户登陆和注销 用户管理添加用户修改用户密码删除用户查询用户信息切换用户查看当前用户用户组的添加和删除用户和组相关文件 实用指令指定运行级别init 命令帮助指令文件目录类时间日期类搜索查找类🔍压缩和…

新能源汽车直流充电桩和交流充电桩的区别

直流充电桩和交流充电桩的区别 你是否曾经想过,为什么有的电动汽车可以在半小时内充满电,而有的却需要几个小时?其实,这都取决于它们所使用的充电桩的不同。那么,直流充电桩和交流充电桩到底有哪些区别呢? 首先,工作…

网络变压器配套使用的网口连接器的选型注意事项及选购关注要点

Hqst盈盛(华强盛)电子导读:采购人员在网口连接器选型中如何选用到合适的产品,选用时要注意到哪些事项,这节将结合网口连接器实物和大家一起探讨,希望对大家有些帮助。 我们可以通过对下面五个方面的详细了解…

网工内推 | 售前、售后工程师,IE认证优先

01 广州佳杰科技有限公司 招聘岗位:IT售前工程师 职责描述: 1、负责所在区域 IT 产品的售前技术支持工作,包括客户交流、方案编写、配置报价、投标应标、测试、赋能等; 2、与厂商相关人员建立和保持良好的关系,相互配合,提高项目成功率和厂商满意度; 3、…

每日一题——链表中倒数最后k个结点

题目 输入一个长度为 n 的链表,设链表中的元素的值为 ai ,返回该链表中倒数第k个节点。 如果该链表长度小于k,请返回一个长度为 0 的链表。 数据范围:0≤n≤$105,0≤ai≤109,0≤k≤109 要求:…

MongoDB索引结构,到底是B-Tree还是B+Tree,请看这里!!

起因 网上关于MongoDB的索引结构到底是b树,还是b树的争论有很多,无法统一结论。 由来 MongoDB从3.2版本开始默认采用了WiredTiger存储引擎,网上很多说法是此引擎是BTree的索引结构,甚至有图有真相。但是认为MongoDB一直是B-Tre…

Docker compose(容器编排)

Docker compose(容器编排) 一、安装Docker compose 1.安装Docker compose Docker Compose 环境安装 Docker Compose 是 Docker 的独立产品,因此需要安装 Docker 之后在单独安装 Docker Compose#下载 curl -L https://github.com/docker/co…

htmlCSS-----定位

目录 前言 定位 分类和取值 定位的取值 1.相对定位 2.绝对位置 元素居中操作 3.固定定位 前言 今天我们来学习html&CSS中的元素的定位,通过元素的定位我们可以去更好的将盒子放到我们想要的位置,下面就一起来看看吧! 定位 定位posi…

HR SaaS厂商,进入决赛圈

在愈发需要降本增效的节点,数字化的价值也更在被越来越多的企业重新审视,这种重视不再是之前或有或无的可选项,而是基于真正人效比维度的必选项 作者|斗斗 编辑|皮爷 出品|产业家 SaaS行业,正在发生一些微妙的变化。 以HR …

如何提高小程序UV?实用策略助你增加用户规模和活跃度

摘要:小程序的UV(Unique Visitors)是衡量用户规模和活跃度的重要指标,对于开发者和运营者来说具有重要意义。本文将分享一些实用策略,帮助你提高小程序的UV,增加用户规模和活跃度。从优化推广渠道、提升用户…

css实现鼠标滑动左下角弹框带动画效果

代码 <div classNamekuang></div> css代码 .kuang {height: 500px;width: 400px;// background-color: #fff;position: absolute;z-index: 10;bottom: 0;transform: translateX(-390px)}.kuang:hover {animation: myanimation 3s linear 1;animation-fill-mode:f…

LT9211C 是一款MIPI/RGB/2PORT LVDS互转的芯片

LT9211C 1.描述&#xff1a; Lontium LT9211C是一个高性能转换器&#xff0c;可以在MIPI DSI/CSI-2/双端口LVDS和TTL之间相互转换&#xff0c;除了24位TTL到24位TTL&#xff0c;并且不推荐同步和DE的2端口10位LVDS和24位TTL之间的转换。LT9211C反序列化输入的MIPI/LVDS/TTL视…

认识雪花id

首先,个人理解,雪花id不是全球的,它只能保证一个分布式服务的范围内的ID是不重复的. 一.SnowFlake 雪花算法 SnowFlake 中文意思为雪花&#xff0c;故称为雪花算法。最早是 Twitter 公司在其内部用于分布式环境下生成唯一 ID。在2014年开源 scala 语言版本。 雪花算法的原理…

项目经理好,还是产品经理好?

我首先介绍一下产品经理和项目经理的区别&#xff0c;然后再说一下产品经理和项目经理的薪资差距&#xff0c;然后你自己决定做产品经理还是项目经理。 1、产品经理和项目经理的区别&#xff1a; 产品经理和项目经理的不同之处在于&#xff0c;产品经理注重思考&#xff0c;关…