Task与 async 和await关键字使用和探讨

基本概念: 

  • Task (任务): 在 .NET 中,Task 表示一个可能会在未来完成的操作,可以是异步的,也可以是同步的。Task<TResult> 是返回结果的任务,而 Task 是不返回结果的任务。
  • async 关键字: 标记一个方法为异步方法。此方法可以包含 await 关键字,用于异步等待其他任务。async 方法的返回类型通常是 TaskTask<TResult>,如果不返回任何值,也可以是 void(不过在实践中,void 仅限于事件处理程序)。
  • await 关键字: 用来暂停(等待方法)异步方法的执行,直到 Task 完成。当任务完成时,代码会继续执行。

async和await简单写法:

写一个简单的异步方法,用Task.Run模拟跑一个任务,用await关键字:来等待这个任务执行完成,

async 关键字: 标记一个方法为异步方法。

public static async Task<int> DoSomethingAsync(){// 同步部分Console.WriteLine("Start");// 异步部分,假设这是一个耗时的I/O操作int result = await Task.Run(() =>{Thread.Sleep(10000); // 模拟长时间的操作return 42;});// 当异步任务完成后,恢复执行Console.WriteLine("End");return result;}public static DateTime GetDate() { return DateTime.Now;}
调用异步方法:

调用异步方法必须是用await来等待,该方法执行结束,不然无法调用,使用await之后必然要使用async标记调用方法要不然会报错,且返回值必须是用Task关键字处理异步任务并且返回一个 Task 对象,要不然也会报错。

     static  async Task Main(string[] args){Console.WriteLine("Hello, World!");int result = await  DoSomethingAsync();Console.WriteLine($"Result: {result}");var date=  GetDate();Console.WriteLine("当前时间",date.ToString()) ;}
简单使用总结: 
  1. Main 方法在执行时,调用了 await DoSomethingAsync()
  2. 此时,Main 方法暂停执行,等待 DoSomethingAsync() 完成。
  3. DoSomethingAsync() 执行完毕并返回结果后,await 会恢复 Main 的执行,继续运行后面的代码。

await和线程的关系:

await调用的等待期间,.net会把当前的线程返回给线程池,等待异步方法调用执行完毕后,框架会从线程池在取出来一个线程执行后续代码。

运行下面的简单的一个文件写入代码,调用await后线程id已经改变了

    static  async Task Main(string[] args){//打印当前线程idConsole.WriteLine(Thread.CurrentThread.ManagedThreadId);StringBuilder sb = new StringBuilder();for (int i = 0; i < 10000; i++){sb.Append("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");}await File.WriteAllTextAsync(@"D:\移动\asp.net core\task和asnyc、await\test\1.txt",sb.ToString());Console.WriteLine(Thread.CurrentThread.ManagedThreadId);}

执行结果:

异步方法不等于多线程:

异步方法的代码并不会自动在新线程中执行,除非把代码放到新线程中执行。

 写一个异步方法但里面没有用到await关键字

虽然这个方法是异步的 (async),但它没有切换线程,仍然在原来的线程上执行。这是因为 async 并不会自动创建新线程。

        //虽然看起来是异步的 但是方法体内并没有创建新线程 所以还是在原来的线程上运行public static async Task<double> CalcAsync(int n){Console.WriteLine("CalcAsync" + Thread.CurrentThread.ManagedThreadId);double result = 0;Random random = new Random();for (int i = 0; i < n * n; i++){result += random.NextDouble();}return result;}
  • async 关键字的主要作用是允许你在方法内部使用 await 来等待异步操作的完成,但它本身并不创建新线程
  • 如果没有 await 或者没有明确的异步操作,整个方法会像普通的同步方法一样执行,只不过它是以异步的形式返回 Task
  • 只有当你使用了 await 等待某个异步任务时,才会暂停当前方法的执行,等待该异步任务完成后继续执行。

 

 调用上面的异步方法

     static  async Task Main(string[] args){Console.WriteLine("执行之前:"+Thread.CurrentThread.ManagedThreadId);double r = await CalcAsync(5000);Console.WriteLine("执行之后:" + Thread.CurrentThread.ManagedThreadId);}

执行结果:

线程id没有改变,因为异步方法不会自动在新线程中执行,想让异步方法在新的线程执行,必须手动设置到新的线程中执行。例如使用Task.Run。

       public static async Task<double> CalcAsync(int n){return await     Task.Run(() =>{Console.WriteLine("CalcAsync" + Thread.CurrentThread.ManagedThreadId);double result = 0;Random random = new Random();for (int i = 0; i < n * n; i++){result += random.NextDouble();}return result;});}

但是Task.Run 不也会直接创建新线程,而是将任务提交给 .NET 线程池,并在池中某个空闲的线程上执行 ,这种方式叫做线程调度,方法将任务委托给线程池来执行, 是异步编程的基础之一。

Task类的是什么?

Task 类是 .NET 中表示异步操作的核心类。它代表一个将来会完成的操作(任务)。Task 可以异步执行,并且允许你等待任务的完成,获取返回值或处理异常。

有两种常用的 Task 类型:

Task:代表一个没有返回值的异步操作(类似于 void)。

Task<T>:代表一个异步操作,返回类型为 T 的结果。

例如:

处理多个并发任务

使用 Task.WhenAll 可以等待多个任务并发完成,这对于并行处理多个独立的异步操作非常有用。

写一个方法,模拟一个需要长时间执行的任务。

    static void DoWork(int taskId){Console.WriteLine($"Task 任务{taskId} 正在执行...");Task.Delay(2000).Wait();  // 模拟长时间任务Console.WriteLine($"Task 任务{taskId}执行完成.");}

调用,并使用Task.WhenAll 对个任务并发进行处理。

   static  async Task Main(string[] args){Task task1 = Task.Run(() => DoWork(1));Task task2 = Task.Run(() => DoWork(2));Task task3 = Task.Run(() => DoWork(3));await Task.WhenAll(task1, task2, task3); // 等待所有任务完成Console.WriteLine("All tasks completed.");Console.ReadKey();}

运行结果:

 WhenAll将方法三个方法一起并行执行完成。

Task.WhenAll 的使用场景

  1. 并行处理:当你有多个独立的任务且它们可以并行执行时,例如批量调用 Web API、并发读取文件等,可以使用 Task.WhenAll
  2. 批量执行并等待完成:在一个应用程序中,你可能需要执行多个异步操作并确保它们全部完成,比如启动多个数据库查询或网络请求,可以使用 Task.WhenAll 确保所有操作完成后再继续后续逻辑。
  3. 等待异步操作的集合:当你有一系列异步任务(可能数量动态变化)时,可以将这些任务打包在一起使用 Task.WhenAll 等待完成。
总结WhenAll方法
  • Task.WhenAll 是处理多个异步任务的强大工具,它不仅可以让你并行执行任务,还能确保所有任务完成后再继续执行后续逻辑。
  • 它还能够聚合多个任务的结果,适合并行操作的场景。
  • 对于异常处理,Task.WhenAll 会将所有任务中的异常一起处理,方便你处理多个异常场景。

通过 Task.WhenAll,你可以轻松管理并行任务和异步操作,提升应用的并发处理能力。

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

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

相关文章

Linux:进程的创建、终止和等待

一、进程创建 1.1 fork函数初识 #include pid_t fork(void); 返回值&#xff1a;子进程中返回0&#xff0c;父进程返回子进程id&#xff0c;出错返回-1 调用fork函数后&#xff0c;内核做了下面的工作&#xff1a; 1、创建了一个子进程的PCB结构体、并拷贝一份相同的进程地址…

JavaScript for循环语句

for循环 循环语句用于重复执行某个操作&#xff0c;for语句就是循环命令&#xff0c;可以指定循环的起点、终点和终止条件。它的格式如下 for(初始化表达式;条件;迭代因子){语句} for语句后面的括号里面&#xff0c;有三个表达式 初始化表达式(initialize):确定循环变量的初始…

27 Vue3之unocss原子化

前置知识 什么是原子化 CSS 原子化 CSS 是一种 CSS 的架构方式&#xff0c;它倾向于小巧且用途单一的 class&#xff0c;并且会以视觉效果进行命名。 为什么使用 原子化 CSS 传统方案 制作原子化 CSS 的传统方案其实就是提供所有你可能需要用到的 CSS 工具。例如&#xff0c…

05:(寄存器开发)定时器一

定时器 1、系统定时器SysTick1.1、SysTick中断的使用1.2、使用SysTick制作延迟函数 2、基本定时器2.1、基本定时器中断的使用2.2、使用基本定时器制作延时函数 1、系统定时器SysTick 1.1、SysTick中断的使用 ①SysTcik系统滴答定时器和片上外设定时器不同&#xff0c;它在CPU…

第十一章 缓存之更新/穿透/雪崩/击穿

目录 一、什么是缓存 二、缓存更新策略 2.1. 缓存主动更新策略 2.1.1. Cache Aside模式&#xff08;主流&#xff09;‌ 2.1.2. Read/Write Through模式‌ 2.1‌.3. Write Behind模式‌ 2.1.4. 总结 三、缓存穿透 四、缓存雪崩 五、缓存击穿 5.1. 互斥锁实现 5.1.1…

C语言复习概要(四)

本文 1. 操作符的分类算术操作符关系操作符逻辑操作符 2. 二进制制和进制转换二进制与十六进制的表示进制转换算法 3. 原码、反码和补码原码反码补码 1. 操作符的分类 C语言中的操作符种类繁多&#xff0c;常用的主要操作符可以按照其功能进行如下分类&#xff1a; 算术操作符…

C++关于链表基础知识

单链表 // 结点的定义 template <class T> struct Node { T data ; Node <T> *next; //指向下一个node 的类型与本node相同 } // 最后一个node指针指向Null 生成结点&#xff1a; Node <T> * p new Node < T>; 为结点赋值: p-> data …

【微服务】服务注册与发现 - Eureka(day3)

CAP理论 P是分区容错性。简单来说&#xff0c;分区容错性表示分布式服务中一个节点挂掉了&#xff0c;并不影响其他节点对外提供服务。也就是一台服务器出错了&#xff0c;仍然可以对外进行响应&#xff0c;不会因为某一台服务器出错而导致所有的请求都无法响应。综上所述&…

LabVIEW机床加工监控系统

随着制造业的快速发展&#xff0c;机床加工的效率与稳定性成为企业核心竞争力的关键。传统的机床监控方式存在效率低、无法远程监控的问题。为了解决这些问题&#xff0c;开发了一种基于LabVIEW的机床加工监控系统&#xff0c;通过实时监控机床状态&#xff0c;改进生产流程&am…

PhotoMaker部署文档

一、介绍 PhotoMaker&#xff1a;一种高效的、个性化的文本转图像生成方法&#xff0c;能通过堆叠 ID 嵌入自定义逼真的人类照片。相当于把一张人的照片特征提取出来&#xff0c;然后可以生成你想要的不同风格照片&#xff0c;如写真等等。 主要特点&#xff1a; 在几秒钟内…

[C语言]指针和数组

目录 1.数组的地址 2.通过指针访问数组 3.数组和指针的不同点 4.指针数组 1.数组的地址 数组的地址是什么&#xff1f; 看下面一组代码 #include <stdio.h> int main() { int arr[5] {5,4,3,2,1}; printf("&arr[0] %p\n", &arr[0]); printf(&qu…

【c++】string类 (一)

简介 由于c的历史包袱&#xff0c;c要兼容c语言&#xff0c;c的字符串要兼容c语言&#xff0c;在 C 中&#xff0c;字符串通常使用两种主要的方式来表示&#xff1a; C风格字符串&#xff08;C-style strings&#xff09;&#xff1a; 依然是以 \0 结尾的字符数组。这种表示方…

设置服务器走本地代理

勾选&#xff1a; 然后&#xff1a; git clone https://github.com/rofl0r/proxychains-ng.git./configure --prefix/home/wangguisen/usr --sysconfdir/home/wangguisen/etcmakemake install# 在最后配置成本地代理地址 vim /home/wangguisen/etc/proxychains.confsocks4 17…

Web安全 - 文件上传漏洞(File Upload Vulnerability)

文章目录 OWASP 2023 TOP 10导图定义攻击场景1. 上传恶意脚本2. 目录遍历3. 覆盖现有文件4. 文件上传结合社会工程攻击 防御措施1. 文件类型验证2. 文件名限制3. 文件存储位置4. 文件权限设置5. 文件内容检测6. 访问控制7. 服务器配置 文件类型验证实现Hutool的FileTypeUtil使用…

计算机网络:计算机网络体系结构 —— OSI 模型 与 TCP/IP 模型

文章目录 计算机网络体系结构OSI 参考模型TCP/IP 参考模型分层的必要性物理层的主要问题数据链路层的主要问题网络层的主要问题运输层的主要问题应用层的主要问题 分层思想的处理方法发送请求路由器转发接受请求发送响应接收响应 计算机网络体系结构 计算机网络体系结构是指将…

简单部署vue+springboot项目

vue 参考博客 先将vue项目打包 npm run build 再创建项目文件夹front,在front中新建nginx.conf server {listen 80;server_name localhost;# 请求体的大小限制client_max_body_size 50m;# 日志文件存放地址access_log /var/log/nginx/host.access.log main;error…

openpnp - 图像传送方向要在高级校正之前设置好

文章目录 openpnp - 图像传送方向要在高级校正之前设置好笔记图像传送方向的确定END openpnp - 图像传送方向要在高级校正之前设置好 笔记 图像传送方向和JOG面板的移动控制和实际设备的顶部摄像头/底部摄像头要一致&#xff0c;这样才能和贴板子时的实际操作方向对应起来。 …

C++ | Leetcode C++题解之第456题132模式

题目&#xff1a; 题解&#xff1a; class Solution { public:bool find132pattern(vector<int>& nums) {int n nums.size();vector<int> candidate_i {nums[0]};vector<int> candidate_j {nums[0]};for (int k 1; k < n; k) {auto it_i upper_…

测试-BUG篇

文章目录 软件测试的生命周期BUGbug的概念描述bug的要素bug级别bug的生命周期 与开发产生争执怎么办&#xff08;高频考题&#xff09; 软件测试的生命周期 软件测试贯穿于软件的整个生命周期 BUG bug的概念 是指计算机程序中存在的一个错误(error)、缺陷(flaw)、疏忽(mista…

docker环境下配置cerbot获取免费ssl证书并自动续期

文章目录 实践场景了解certbot查看nginx的映射情况操作目标配置nginx配置的ssl证书设置自动续签 实践场景 本人使用docker部署了一个nginx容器&#xff0c;通过容器卷&#xff0c;实现本地html&#xff0c;ssl&#xff0c;conf和ngiinx容器映射的&#xff0c; 经常需要手动部署…