如何在 .NET Core 中轻松实现异步编程并提升性能

目录

初识异步编程

与多线程关系

异步编程操作


初识异步编程

        异步编程:是指在执行某些任务时程序可以在等待某个操作完成的过程中继续执行其他任务,而不是阻塞当前线程,这在处理I/O密集型操作(如文件读取、数据库查询、网络请求等)时尤为重要,能够显著提高应用程序的性能和响应能力。

在.net core中异步编程主要通过asyncawait关键字来实现,结合Task类进行异步操作的管理:

async:标记方法为异步方法使其能够包含await表达式

await:在异步方法中用于等待一个异步操作完成,允许方法在等待期间继续执行其他代码而不会阻塞线程

异步方法通常返回TaskTask<T> 类型:

Task:表示一个没有返回值的异步操作

Task<T>:表示一个带返回值的异步操作,其中T是返回值的类型

        作用意义:在进行项目开发的时候通常都会遇到异步编程的使用方式,具备的意义如下:

1)提高应用程序响应性:异步编程可以使得应用程序在等待长时间操作(例如网络请求或文件读写)时继续处理其他任务而不会卡住主线程,比如在桌面应用或Web应用中用户界面不会因等待数据加载而变得无响应

2)提升性能:传统的同步编程会阻塞线程直到操作完成,这可能导致线程资源的浪费,特别是在高并发场景下异步编程允许线程释放去处理其他任务,避免了线程饥饿问题,最大化利用CPU资源特别是在I/O密集型操作时

3)节省资源:异步操作不需要为每个操作分配新的线程,因此能够节省系统资源,在高并发情况下异步编程可以显著减少上下文切换开销

4)适用于I/O密集型应用:异步编程特别适用于那些需要大量I/O操作的应用,例如网络请求、磁盘读取、数据库查询等。通过异步操作可以避免长时间等待I/O操作而导致的性能瓶颈

接下来我们通过异步方法从指定的URL路径上下载网页内容,将网页内容保存到本地文件并输出下载的内容的字节数,代码结果如下所示:

using System;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;namespace Program
{class Program{static async Task Main(string[] args){int len = await DownloadHtmlAsync("https://www.baidu.com", @"d:\test\1.txt");Console.WriteLine($"Downloaded {len} bytes.");}static async Task<int> DownloadHtmlAsync(string url, string filename){using (HttpClient client = new HttpClient()){string html = await client.GetStringAsync(url);await File.WriteAllTextAsync(filename, html);return html.Length;}}}
}

与多线程关系

异步编程并不等于多线程,这是两个概念,异步方法的代码并不会自动在新线程中执行,除非把代码放到新线程中执行,以下做一个简单的演示:

使用异步方法来执行长时间运行的计算,通过Thread.CurrentThread.ManagedThreadId输出当前执行线程的ID,可以看到异步方法和线程调度的关系如下,这里我们通过计算5000*5000的情况避免执行太快:

using System;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;namespace Program
{class Program{static async Task Main(string[] args){Console.WriteLine("之前:" + Thread.CurrentThread.ManagedThreadId);double r = await CalcAsync(5000);Console.WriteLine("之后:" + Thread.CurrentThread.ManagedThreadId);}static async Task<double> CalcAsync(int n){Console.WriteLine("CalcAsync" + Thread.CurrentThread.ManagedThreadId);double result = 0;Random rand = new Random();for (int i = 1; i <= n*n; i++){result += rand.NextDouble();}return result;}}
}

那么如何在新的线程中执行异步方法呢?这里我们必须手动将异步方法放到新的线程中,这里我们只需要将要执行的代码以委托的形式传递给Task.Run(),这样就会从线程池中取出一个线程来执行我们的委托,如下可以看到我们的线程已经发送了变化:

如果一个异步方法只是对别的异步方法调用转发,并没有太多复杂的逻辑,那么就可以去掉异步关键字直接返回Task,如下所示:

对于多线程来讲,在await调用的等待期间.net会把当前的线程返回给线程池,等异步方法调用执行完毕之后,框架会从线程池再取出一个线程执行后续代码,怎么理解?比如说你进入一家餐馆服务器给你递上一个菜单,在等待你选菜的时候服务你的服务员可能会继续服务别人,当你点餐完毕提交给服务员之后,服务你的服务员可能就不是刚刚服务你的人了,就是这么个意思,当然如果异步等待时间极短,线程可能就不会发送变化:

尽管异步编程和多线程都涉及到并发执行任务,但它们的工作原理和适用场景有所不同,可以把它们看作是两个不同的工具用于解决不同类型的并发问题:

异步编程:通过非阻塞的方式执行操作,适用于 I/O 密集型任务,能够节省线程资源提高应用的响应性。

多线程:通过并行执行任务来提高CPU密集型任务的性能,但线程管理复杂可能带来上下文切换和同步问题。

异步编程与多线程的结合:异步编程通过减少阻塞来提高效率而多线程通过并行执行来加速计算密集型任务,在某些情况下它们可以结合使用:例如异步任务通过线程池线程执行,充分利用多核处理器的计算能力。

异步编程操作

异步等待:如果想在异步方法中暂停一段时间的话,这里可以使用 await Task.Delay()的方式,例如下载一个网址然后等待3秒再下载另一个,注意这里是不能使用Thread.Sleep()方法的,该方法是阻塞线程用的,异步编程并不适用,这里我们演示一下异步等待的效果,如下所示:

class Program
{static async Task Main(string[] args){var input = Console.ReadLine();Console.WriteLine(input);await Task.Delay(3000);Console.WriteLine(input+".net core");}
}

异步取消:在异步编程中CancellationToken是用于取消异步操作的一种机制,它提供了一种优雅的方式来中止正在进行的操作,当用户操作可能会长时间运行时,例如下载文件、访问数据库、调用远程API等,CancellationToken用于支持任务的取消操作,示例如下:

class Program
{static async Task Main(string[] args){CancellationTokenSource cts = new CancellationTokenSource();cts.CancelAfter(3000);CancellationToken cToken = cts.Token;await Download1Async("https://www.baidu.com", 100, cToken);}static async Task Download1Async(string url, int n, CancellationToken token){using(HttpClient client = new HttpClient()){for (int i = 0; i < n; i++){string html = await new HttpClient().GetStringAsync(url);Console.WriteLine($"{DateTime.Now}:{html}");if (token.IsCancellationRequested){Console.WriteLine("超时任务取消");break;}}}}
} 

当我们打印数据的时候,请求超过5秒还没有结束的话我们就手动取消异步操作:

Task类方法:在Task类中有许多方法可以使用,以下是其常用的方法讲解:

1)Task.WhenAny():任何一个Task完成,Task就完成

2)Task.WhenAll():所有Task完成Task才完成,用于等待多个任务执行结束不在乎顺序

3)Task.FromResult():创建普通数值的Task对象

如下我们可同WhenAll拿到所有文件的数据:

class Program
{static async Task Main(string[] args){Task<string> t1 = File.ReadAllTextAsync(@"d:\test\1.txt");Task<string> t2 = File.ReadAllTextAsync(@"d:\test\2.txt");Task<string> t3 = File.ReadAllTextAsync(@"d:\test\3.txt");string[] result = await Task.WhenAll(t1, t2, t3);} 
} 

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

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

相关文章

麒麟操作系统服务架构保姆级教程(二)ssh远程连接

如果你想拥有你从未拥有过的东西&#xff0c;那么你必须去做你从未做过的事情 作为一名成熟运维架构师&#xff0c;我们需要管理的服务器会达到几十台&#xff0c;上百台&#xff0c;上千台&#xff0c;甚至是上万台服务器&#xff0c;而且咱们的服务器还不一定都在一个机房&am…

159.等差数列的划分

class Solution {public int numberOfArithmeticSlices(int[] nums) {int lenums.length;if(le<3){return 0;}int arith0,res0,count0;//arith是差的大小,res是结果,count计算等差数量for(int i1;i<le;i){if(nums[i]-nums[i-1]arith){count;if(count>2){rescount-1;}}…

RabbitMQ消息队列的笔记

Rabbit与Java相结合 引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId> </dependency> 在配置文件中编写关于rabbitmq的配置 rabbitmq:host: 192.168.190.132 /…

纯css 实现呼吸灯效果

开始效果 呼吸效果 实现代码 <div class"container"><div class"breathing-light"></div> </div><style>html,body {height: 100%;background-color: white;}.container {padding: 100px;}.container .breathing-light {wi…

进程通信方式---共享映射区(无血缘关系用的)

5.共享映射区&#xff08;无血缘关系用的&#xff09; 文章目录 5.共享映射区&#xff08;无血缘关系用的&#xff09;1.概述2.mmap&&munmap函数3.mmap注意事项4.mmap实现进程通信父子进程练习 无血缘关系 5.mmap匿名映射区 1.概述 原理&#xff1a;共享映射区是将文件…

《云原生安全攻防》-- K8s安全框架:认证、鉴权与准入控制

从本节课程开始&#xff0c;我们将来介绍K8s安全框架&#xff0c;这是保障K8s集群安全比较关键的安全机制。接下来&#xff0c;让我们一起来探索K8s安全框架的运行机制。 在这个课程中&#xff0c;我们将学习以下内容&#xff1a; K8s安全框架&#xff1a;由认证、鉴权和准入控…

day08-别名-重定向-去重排序等

1.重复用touch命令创建同一份文件&#xff0c;会修改文件的时间戳。 alias命令&#xff1a; 别名 查看已有别名&#xff1a;alias [rootoldboy ~]# alias alias cpcp -i alias egrepegrep --colorauto alias fgrepfgrep --colorauto alias grepgrep --colorauto alias l.ls…

Qt WORD/PDF(四)使用 QAxObject 对 Word 替换(QWidget)

关于QT Widget 其它文章请点击这里: QT Widget 国际站点 GitHub: https://github.com/chenchuhan 国内站点 Gitee : https://gitee.com/chuck_chee 姊妹篇: Qt WORD/PDF&#xff08;一&#xff09;使用 QtPdfium库实现 PDF 操作 Qt WORD/PDF&#xff08;二…

Node的学习以及学习通过Node书写接口并简单操作数据库

Node的学习 Node的基础上述是关于Node的一些基础&#xff0c;总结的还行&#xff1b; 利用Node书写接口并操作数据库 1. 初始化项目 创建新的项目文件夹&#xff0c;并初始化 package.json mkdir my-backend cd my-backend npm init -y2. 安装必要的依赖 安装Express.js&…

计算机视觉中的特征提取算法

摘要&#xff1a; 本文聚焦于计算机视觉中的特征提取算法&#xff0c;深入探讨尺度不变特征变换&#xff08;SIFT&#xff09;算法。详细阐述 SIFT 算法的原理&#xff0c;包括尺度空间构建、关键点检测、方向分配与特征描述子生成等核心步骤。通过 C#、Python 和 C 三种编程语…

java版询价采购系统 招投标询价竞标投标系统 招投标公告系统源码

功能描述 1、门户管理&#xff1a;所有用户可在门户页面查看所有的公告信息及相关的通知信息。主要板块包含&#xff1a;招标公告、非招标公告、系统通知、政策法规。 2、立项管理&#xff1a;企业用户可对需要采购的项目进行立项申请&#xff0c;并提交审批&#xff0c;查看所…

景联文科技入选中国信通院发布的“人工智能数据标注产业图谱”

近日&#xff0c;由中国信息通信研究院、中国人工智能产业发展联盟牵头&#xff0c;联合中国电信集团、沈阳市数据局、保定高新区等70多家单位编制完成并发布《人工智能数据标注产业图谱》。景联文科技作为人工智能产业关键环节的代表企业&#xff0c;入选图谱中技术服务板块。…

【小沐学GIS】基于C++绘制三维数字地球Earth(OpenGL、glfw、glut、QT)第三期

&#x1f37a;三维数字地球系列相关文章如下&#x1f37a;&#xff1a;1【小沐学GIS】基于C绘制三维数字地球Earth&#xff08;456:OpenGL、glfw、glut&#xff09;第一期2【小沐学GIS】基于C绘制三维数字地球Earth&#xff08;456:OpenGL、glfw、glut&#xff09;第二期3【小沐…

实景视频与模型叠加融合?

[视频GIS系列]无人机视频与与实景模型进行实时融合_无人机视频融合-CSDN博客文章浏览阅读1.5k次&#xff0c;点赞28次&#xff0c;收藏14次。将无人机视频与实景模型进行实时融合是一个涉及多个技术领域的复杂过程&#xff0c;主要包括无人机视频采集、实景模型构建、视频与模型…

MySQL通过binlog日志进行数据恢复

记录一次阿里云MySQL通过binlog日志进行数据回滚 问题描述由于阿里云远程mysql没有做安全策略 所以服务器被别人远程攻击把数据库给删除&#xff0c;通过查看binlog日志可以看到进行了drop操作&#xff0c;下面将演示通过binlog日志进行数据回滚操作。 1、查询是否开始binlog …

IDEA 修改格式化仅格式化本次改动代码

最近总是发现格式化的时候会格式化文件所有代码&#xff0c;提交Git 后再看提交日志&#xff0c;就很不清晰。修改方式如下 中文&#xff1a; 格式化代码快捷键[中文配置]&#xff1a; 英文&#xff1a; 格式化代码快捷键[英文配置]&#xff1a;

【含开题报告+文档+PPT+源码】基于微信小程序的点餐系统的设计与实现

开题报告 随着互联网技术的日益成熟和消费者生活水平与需求层次的显著提升&#xff0c;外卖点餐平台在中国市场上迅速兴起并深深植根于民众日常生活的各个角落。这类平台的核心在于构建了一个基于互联网的强大订餐服务系统&#xff0c;它无缝整合了餐饮商户资源与广大消费者的…

解决 MyBatis 中空字符串与数字比较引发的条件判断错误

问题复现 假设你在 MyBatis 的 XML 配置中使用了如下代码&#xff1a; <if test"isCollect ! null"><choose><when test"isCollect 1">AND exists(select 1 from file_table imgfile2 where task.IMAGE_SEQimgfile2.IMAGE_SEQ and im…

SpringBoot 手动实现动态切换数据源 DynamicSource (中)

大家好&#xff0c;我是此林。 SpringBoot 手动实现动态切换数据源 DynamicSource &#xff08;上&#xff09;-CSDN博客 在上一篇博客中&#xff0c;我带大家手动实现了一个简易版的数据源切换实现&#xff0c;方便大家理解数据源切换的原理。今天我们来介绍一个开源的数据源…

前端学习一

一 进程与线程 线程是进程执行的最小单位&#xff0c;进程是系统分配任务的最小单位。 一个进程可执行最少一个线程。线程分为子线程和主线程。 主线程关闭则子线程关闭。 二 浏览器进程 浏览器是多进程多线程应用。 进程包括&#xff1a; 浏览器进程 负责程序交互渲染…