【.NET Core】异步编程模式

【.NET Core】异步编程模式

文章目录

  • 【.NET Core】异步编程模式
    • 一、概述
    • 二、基于任务的异步模式(TAP)
      • 2.1 TAP模式命名、参数和返回类型
      • 2.2 TAP初始化异步操
      • 2.3 TAP如何编译
      • 2.4 手动生成TAP方法
      • 2.5 混合方法实现TAP
      • 2.6 TAP中Await挂起执行
      • 2.7 TAP中使用Yield和ConfigureAwait配置挂起和恢复
    • 三、基于事件的异步模式(EAP)
    • 四、异步编程模型(APM)
      • 4.1 开始异步操作
      • 4.2 结束异步操作

一、概述

.NET提供了执行异步操作的三种模式:

  • 基于任务的异步模式(TAP),该模式使用单一方法表示异步操作的开始和完成。TAP是在.NET Framework 4 中引入的,这是在.NET中进行异步编程的推荐方法。C#的asyncawait关键词和Await运算符为TAP添加了语言支持。
  • **基于事件的异步模式(EAP)**是提供异步行为的基于事件的旧模型。这种模式需要后缀为Async的方法,以及一个或多个事件,事件处理程序委托类型和EventArg派生类型。EAP是在.NET Framework2.0中引入的。建议新开发中不再使用这种模式。
  • 异步编程模型模式(APM)(也称为IAsyncResult模式),这是使用IAsyncResult接口提供异步行为的旧模型。在APM模式下,同步操作需要Begin和End方法。不建议新的开发使用此模式。

二、基于任务的异步模式(TAP)

在.NET中,基于任务的异步模式是建议用于新开发的异步设计模式。它是基于System.Threading.Tasks命名中的TaskTask<TResult>类型,这个类型用于表示异步操作。

2.1 TAP模式命名、参数和返回类型

TAP使用单个方法表示异步操作的开始和完成。这与异步编码模型(APMIAsyncReult)模式和基于事件的异步模式(EAP)形成对比。APM需要BeginEnd方法。EAP需要后缀为Async的方法,以及一个或多个事件,事件处理程序委托类型和EventArg派生类型。

TAP中的异步方法在返回类型

  • System.Threading.Tasks.Task
  • System.Threading.Tasks.Task<TResult>

具体返回类型取决于相应的同步方法返回的是void还是类型TResult

TAP异步方法参数

TAP方法的参数应与其同步对应方法的参数匹配,并应以相同顺序提供。但是,outref参数不受此规则的限制,并应完全避免。应该将通过outref参数返回的所有数据改为作为由TResult返回的Task<TResult>的一部分返回,且应使用元组或自定义数据结构来容纳多个值。即使TAP方法的同步对应项没有提供CancellationToken参数,也应考虑添加此参数。

2.2 TAP初始化异步操

基于TAP的异步方法可以同步完成少量工作,如在返回结果任务之前,验证自变量和启动异步操作。应将同步工作保持最小,以便异步方法可以快速返回。快速返回的原因包括:

  • 可以从用户界面线程调用异步方法,因此,所有长期运行的同步工作可能会降低应用程序的响应能力。
  • 可以同时启动多个异步方法,因此,在异步方法的同步部分中的任何长时间运行的工作都可以延迟其他异步操作的启动,从而减少并发的优点。

2.3 TAP如何编译

自.NET Framework 4.5起,任何归于async关键字的方法都被视为异步方法,并且编译器会执行必要的转换,以使用TAP异步实现方法。异步方法应返回System.Treading.Tasks.TaskSystem.Threading.Tasks.Task<TResult>对象。对于后者,函数的主体应该返回TResult,并且编译器确保此结果是通过生成的任务对象获得。同样,未在方法的主体中处理的任何异常都会被封装处理未输出任务并导致生成的任务结束以TaskStatus.Faulted状态结束。此规则的异常发生在OperationCanceledException未得到处理时,在这种情况下生成的任务以TaskStatus.Canceled状态结束。

2.4 手动生成TAP方法

手动实现TAP模式以更好的控制实现。编译器依赖从System.Threading.Tasks命名空间公开的公共外围应用和System.Runtime.CompilerServices命名空间中支持的类型。手动实现TAP,需要创建一个TaskCompletionSource<TResult>对象,执行异步操作,并在操作完成时,调用SetResultSetExceptionSetCanceled方法或调用这些方法之一的Try版本。手动实现TAP方法时,需在所在表示的异步操作完成生成的任务。例如:

public static Task<int> ReadTask(this Stream stream,byte[] buffer,int offset,int count,object state)
{var tcs =new TaskCompletionSource<int>();stream.BeginRead(buffer,offset,count,resp=>{try{tcs.SetResult(stream.EndRead(resp));}catch(Exception ex){tcs.SetException(ex);}},state);return tcs.Task;
}

2.5 混合方法实现TAP

混合方法可以将核心逻辑委托给编译器。如果想验证编译器生成的异步方法之外的参数时,可能需要使用这种混合方法,以便异常可以转义到该方法的直接调用方而不是通过System.Threading.Tasks.Task对象被公开:

public Task<int> MethodAsync(string input)
{if(input==null) throw new ArgumentNullException("input");return MethodAsyncInternal(input);
}
private async Task<int> MethodAsyncInternal(string input)
{return value;
}

2.6 TAP中Await挂起执行

使用await关键字开异步等待TaskTask<TResult>对象。等待Task时,await表达式的返回类型为void。等待Task<TResult>时,await表达式的类型为TResultawait表达式必须出现在异步方法的正文内。

实际上,await 功能通过使用延续任务在任务上安装回叫。此回叫在挂起点恢复异步方法。 恢复异步方法时,如果等待的操作已成功完成且为Task<TResult>,返回的是TResult。如果等待的TaskTask<TResult>以Canceked状态结束。就会抛出OpetationCanceledException异常。如果等待的TaskTask<TResult>Faulted状态结束,就会抛出导致它发生故障的异常。一个Task可能由于多个异常而出错,但只会传播一个异常。不过Task.Exception属性会返回包含所有错误AggregateException异常。

调用异步方法时,将同步执行函数的正文,直到遇见尚未完成的可等待实例上的第一个 await 表达式,此时调用返回到调用方。如果异步方法不返回void,将会返回TaskTask<TResult>对象,以表示正在进行的计算。在非void异常方法中,如果遇到return语句或到达方法正文末尾,任务就以RanToCompletion最终状态完成。如果未经处理的异常导致无法控制异步方法正文,任务就以Faulted状态结束。如果异常为OperationCanceledException,任务改为以Canceled状态结束。

2.7 TAP中使用Yield和ConfigureAwait配置挂起和恢复

使用Task.Yield方法,将暂停点引入异步方法。

Task.Run(async delegate{int flag=0;do{await Task.Yield();flag++;}while(flag<10000);
});

使用Task.ConfigureAwait方法,更好地控制异步方法中的暂停和恢复。默认情况下,异步方法挂起时会捕获当前上下文,捕获的上下文用于在恢复时调用异步方法的延续。

三、基于事件的异步模式(EAP)

System.Threading命名空间提供了创建高性能多线程应用程序所必需的所有工具,但要想有效地使用这些工具,需要有丰富的使用多线程软件工程的经验。对于相对简单的多线程应用程序,BackgroundWorker组件提供了一个简单的解决方案。对于更复杂的异步应用程序,考虑实现一个符合基于事件的异步模式的类。

基于事件的异步模式具有多线程应用程序的优点,同时隐藏了多线程设计中固有的许多复杂的问题。使用EAP模式的能够:

  • “在后台”执行耗时任务(例如下载和数据库操作),但不会中断你的应用程序。
  • 同时执行多个操作,每个操作完成时都会接到通知。
  • 等待资源变得可用,但不会停止(“阻止”)你的应用程序。
  • 使用熟悉的事件和委托模型与挂起的异步操作通信。

支持基于事件的异步模式的类将具有一个或多个命名为 MethodNameAsync 的方法。 这些方法可能会创建同步版本的镜像,这些同步版本会在当前线程上执行相同的操作。 该类还可能具有 MethodNameCompleted 事件,并且可能会具有 MethodNameAsyncCancel(或只是 CancelAsync)方法。

EAP常用的组件:

许多组件都支持异步执行工作,常用的有SoundPlayer和PictureBox组件,可以“在后台”加载音频和图像,同时主线程继续运行而不中断。

四、异步编程模型(APM)

使用IAsyncResult设计模式的异步操作时通过名微BeginOperatiobNameEndOperationName的两个方法来实现的,这两个方法分别开始和结束异常操作OperationName。例如:FileStream类提供BeginReadEndRead方法来从文件异步读取字节。

在调用BeginOperationName后,应用程序可以继续在调用线程上执行指令,同时异步操作在另一个线程上执行。每次调用BeginOperationName时,应用程序还调用EndOperationName来获取操作的结果。

4.1 开始异步操作

BeginOperationName方法开始异步操作OperationName,并返回实现IAsyncResult接口的对象。IAsyncResult对象存储有关异步操作的信息。

编号成员描述
1AsyncState一个特定应用程序的可选对象,其中包含有关异步操作的信息
2AsyncWaitHandle一个WaitHandle,可用来在异步操作完成之前阻止应用程序执行。
3CompletedSynchronously一个指,指示异步操作是否是在用于调用BeginOperationName的线程上完成,而不是在单独的ThreadPool线程上完成。
4IsCompleted一个值,指示异步操作是否已完成。

BeginOperationName 方法采用该方法的同步版本的签名中声明的任何参数(由值传递或由引用传递)。 BeginOperationName 方法签名中不包含任何输出参数。 BeginOperationName 方法签名另外还包括两个其他参数。 第一个参数定义一个 AsyncCallback委托,此委托引用在异步操作完成时调用的方法。 如果调用方不希望在操作完成后调用方法,它可以指定 null (在 Visual Basic 中为Nothing )。 第二个参数是一个用户定义的对象。 此对象可用来向异步操作完成时调用的方法传递应用程序特定的状态信息。 如果 BeginOperationName 方法还采用其他一些操作特定的参数(例如,一个用于存储从文件读取的字节的字节数组),则 AsyncCallback和应用程序状态对象将是 BeginOperationName 方法签名中的最后两个参数。

BeginOperationName 立即返回对调用线程的控制。 如果 BeginOperationName 方法引发异常,则会在开始异步操作之前引发异常。 如果 BeginOperationName 方法引发异常,则意味着没有调用回调方法。

4.2 结束异步操作

EndOperationName方法用于结束异步操作OperationNameEndOperationName方法的返回值与其同步对应方法的返回值类型相同。并且是特定于异步操作的。

EndOperationName方法采用该方法同步版本的签名中声明的所有输出参数或引用参数。

如果调用EndOperationNameIAsyncResult对象表示的异步操作尚未完成,则EndOperationName将在异步操作完成之前阻止调用线程。异步操作引发的异常是从EndOperationName方法引发的。未定义多次使用同一IAsyncResult调用EndOperationName方法的效果。

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

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

相关文章

记一次canal除坑记录

记一次canal除坑记录 错误信息 Caused by :com.alibaba.otter.canal.parse.exception.CanalParseException: column size is not match for table 问题处理 今天对Canal相关程序进行升级&#xff0c;原监听的表及业务都正常&#xff1b;遇到新增加的表时总是不走&#xff1b;…

202402读书笔记|《当你老了》——灰蒙曙光比爱情温柔,清晨露珠比希望更可爱

202402读书笔记|《当你老了》——灰蒙曙光比爱情温柔&#xff0c;清晨露珠比希望更可爱 《当你老了》作者叶芝&#xff0c;断断续续碎片时间读完的一本书&#xff0c;不是很惊艳&#xff0c;但值得一读。就因为很喜欢当你老了&#xff0c;所以拾起的这本书。读完知道了原来叶芝…

什么是软件安全性测试?如何进行安全测试?

一、什么是软件安全性测试&#xff1f; 软件安全性测试是指对软件系统中的安全漏洞进行检测和评估的过程。其目的是为了确保软件系统在面对各种安全威胁时能够保持其功能的完整性、可用性和机密性。 二、软件安全性测试可以通过以下几个步骤来进行&#xff1a; 1. 需求分析&a…

[实践总结] 限制正则表达式匹配次数/时间 防止DoS攻击

思路 1、优化正则表达式 2、正则表达式无法优化的话&#xff0c;可以考虑限制匹配次数&#xff0c;或者限制匹配时间 限制 匹配次数 public class CountedCharSequence implements CharSequence {private final CharSequence charSequence;private long count;public Counte…

51单片机四位数码管计算器 Proteus仿真程序

目录 概要 仿真图 部分代码 资料下载地址&#xff1a;51单片机四位数码管计算器 Proteus仿真程序 概要 1.系统通过4x4的矩阵键盘输入数字及运算符。 2.可以进行4位十进制数以内的加法运算&#xff0c;如果计算结果超过4位十进制数&#xff0c;则屏幕显示E 3.可以进行加法以外…

LowB三人组(冒泡排序,插入排序,选择排序)(数据结构课设篇1,python版)(排序综合)

本章博客主要详细讲解一下LowB三人组排序&#xff0c;为什么叫LowB三人组呢&#xff1f;因为他们的时间复杂度都为O&#xff08;n^2&#xff09;。下篇博客会再讲解NB三人组&#xff08;堆排序&#xff0c;归并排序和快速排序&#xff09;&#xff0c;第三篇博客会讲解其他排序…

算法每日一题:队列中可以看到的人数 | 单调栈

大家好&#xff0c;我是星恒 今天是一道困难题&#xff0c;他的题解比较好理解&#xff0c;但是不好想出来&#xff0c;接下来就让我带大家来捋一捋这道题的思路&#xff0c;以及他有什么特征 题目&#xff1a;leetcode 1944有 n 个人排成一个队列&#xff0c;从左到右 编号为 …

Spring国际化的应用及原理详解

1. 简介 Spring国际化&#xff08;Spring Internationalization&#xff0c;简称i18n&#xff09;是Spring框架提供的一种机制&#xff0c;用于支持多语言的应用程序。它使得开发者能够轻松地在应用程序中实现不同语言的支持&#xff0c;从而满足全球化的需求。通过Spring国际…

面试必问究极重点之HashMap的底层原理

1.底层数据结构 JDK版本不同的数据结构 1.7 数组 链表 1.8 数组 &#xff08;链表 | 红黑树&#xff09; 2.添加数据put 在添加一个值的时候&#xff0c;首先会计算他的hash码&#xff0c;然后进行二次hash&#xff0c;在对当前长度取模得到在底层数组中的索引位置当取模完…

浅谈软件架构设计

软件架构基本知识&#xff1a; 关于软件架构&#xff0c;其实没有一个特定的定论。之所以要有软件架构&#xff0c;个人觉得是从逻辑上抽象出一些通用的设计模式&#xff0c;设计方法&#xff0c;开发框架&#xff0c;实现步骤&#xff0c;工程管理等。从容让软件开发&#xff…

electron——查看electron的版本(代码片段)

electron——查看electron的版本(代码片段)1.使用命令行&#xff1a; npm ls electron 操作如下&#xff1a; 2.在软件内使用代码&#xff0c;如下&#xff1a; console.log(process) console.log(process.versions.electron) process 里包含很多信息&#xff1a; process详…

【Linux】——基本指令(二)

&#x1f497;个人主页&#x1f497; ⭐个人专栏——数据结构学习⭐ &#x1f4ab;点击关注&#x1f929;一起学习C语言&#x1f4af;&#x1f4ab; 目录 导读&#xff1a;1. vim 指令2. head指令3. tail指令4. tree指令5. 输出重定向6. echo指令7. wc指令8. | 字符9. date指令…

PCIe 6.0生态业内进展分析总结

上一篇&#xff0c;我们针对PCIe 6.0的功能更新与实现挑战做了简单的分析与总结。更多详细内容可以参考&#xff1a; 扩展阅读&#xff1a;浅析PCIe 6.0功能更新与实现的挑战 那么&#xff0c;PCIe 6.0已经发布了一段时间了&#xff0c;业内硬件支持PCIe 6.0目前有哪些进展呢…

Spring Security 6.x 系列(13)—— 会话管理之会话概念及常用配置

一、会话概念 在实现会话管理之前,我们还是先来了解一下协议和会话的概念,连协议和会话都不知道是啥,还谈啥管理。 1.1 http 协议 因为我们现在的会话,基本上都是基于HTTP协议的,所以在讲解会话之前,我再带各位复习一下HTTP协议。 1.1.1 概念 HTTP:超文本传输协议(…

uniapp获取日期

1.使用new Date()方法获取系统今天的日期&#xff0c;显示格式为&#xff1a;2023-10-28 <template><view class"content">{{date}}</view> </template> <script>export default {data() {return {date: new Date().toISOString().sl…

python开发案例教程-清华大学出版社(张基温)答案(4.2)

目录 练习 4.2 1. 代码分析题 2. 程序设计题 练习 4.2 1. 代码分析题 阅读下面的代码&#xff0c;给出输出结果。 &#xff08;1&#xff09; class A:def __init__(self,a,b,c):self.xabca A(3,5,7);b getattr(a,x);setattr(a,x,b3);print(a.x)18 &#xff08;2&…

python 正则-常见题目

1、邮箱 print(re.findall(r[\w-][\w-]\.[\w-], weidianqq.com))2、身份证号 xxxxxx yyyy MM dd 375 0 十八位 print(re.findall(r(?:18|19|(?:[23]\d))\d{2}, 2010)) # 年print(re.findall(r(?:0[1-9])|10|11|12, 11)) # 月print(re.findall(r(?:[0-2][1-9])|10|20|30|3…

面试算法93:最长斐波那契数列

题目 输入一个没有重复数字的单调递增的数组&#xff0c;数组中至少有3个数字&#xff0c;请问数组中最长的斐波那契数列的长度是多少&#xff1f;例如&#xff0c;如果输入的数组是[1&#xff0c;2&#xff0c;3&#xff0c;4&#xff0c;5&#xff0c;6&#xff0c;7&#x…

外包干了5个月,技术明显退步了...

先说一下自己的情况&#xff0c;本科生&#xff0c;19年通过校招进入湖南某软件公司&#xff0c;干了接近4年的功能测试&#xff0c;今年12月份&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能测…

周鸿祎分享大模型十大趋势:2024将出现杀手级应用

1月5日&#xff0c;“2023年风马牛年终秀”上&#xff0c;三六零&#xff08;601360.SH&#xff0c;下称“360”&#xff09;集团创始人周鸿祎分享了对2024年大模型发展趋势的十大预测&#xff0c;呼吁企业树立AI信仰&#xff0c;All in AI。他认为&#xff0c;创新才能破局&am…