.Net Core自实现CLR异步编程模式(Asynchronous programming patterns)
最近在看一个线程框架,对.Net的异步编程模型很感兴趣,所以在这里实现CLR定义的异步编程模型,在CLR里有三种异步模式如下,如果不了解的可以详细看MSDN 文档Asynchronous programming patterns。
1.Asynchronous Programming Model (APM)异步编程模式(也叫 IAsyncResult 模式),
public class MyClass
{
public IAsyncResult BeginRead(byte [] buffer, int offset, int count,AsyncCallbackcallback, object state);
public int EndRead(IAsyncResult asyncResult);
}
2.Event-based Asynchronous Pattern (EAP)基于事件的异步模式(客户端应用程序善于)
public class MyClass
{
public void ReadAsync(byte [] buffer, int offset, int count);
public event ReadCompletedEventHandler ReadCompleted;
}
3.Task-based Asynchronous Pattern (TAP)基于任务的异步模式(async 和await关键字)
public class MyClass
{
public Task<int> ReadAsync(byte [] buffer, int offset, int count);
}
现在我们基于第一种模式APM模式来自己实现一个异步模式,首先我们需要接触APM的一个重要接口IAsyncResult,他有四个属性需要实现。
namespace System {
public interface IAsyncResult {
object? AsyncState { get; }
WaitHandle AsyncWaitHandle { get; }
bool CompletedSynchronously { get; }
bool IsCompleted { get; }
}
}
这四个对象分别有着自己的功能,IsCompleted是为了轮询查询状态,AsyncWaitHandle 是为了线程同步,AsyncState 是为了回调技术。拥有了这三个对象就可以做一个异步机制。首先我们实现这个接口。
public class DelayTaskAsyncResult : IAsyncResult {
private AsyncCallback _callback;
private object _asyncState;
private ManualResetEvent _resetEvent = new ManualResetEvent(false);
public object result { get; set; }
public DelayTaskAsyncResult(AsyncCallback callback, object state) {
this._callback = callback;
this._asyncState = state;
}
public volatile int _completed = 0;
public void SetCompleted() {
Interlocked.Increment(ref _completed);
_resetEvent.Set();
_callback?.Invoke(this);
}
public object EndInvoke() {
if (!IsCompleted) {
AsyncWaitHandle.WaitOne();
}
return result;
}
public object AsyncState => _asyncState;
public WaitHandle AsyncWaitHandle => _resetEvent;
public bool CompletedSynchronously => throw new NotImplementedException();
public bool IsCompleted => _completed != 0;
}
很简单的实现如上,首先来解释一下这段代码,_callback和_asyncState是作为回调技术使用的,_resetEvent是为了线程同步技术使用的,result接口是异步处理后得到的结果,_completed作为线程处理状态的标记,加了volatile保证原子性保证多线程模式下拿到的值是最新的,SetCompleted方法是在线程执行完毕之后执行更新IAsyncResult其中的状态,先将状态值_completed自增,然后设置通过的信号量,有回调方法执行回调,而EndInvoke方法中如果没有执行完就等待信号量,如果执行完就返回执行结果。
现在接口已经实现完成,现在需要定义自己想要的任务对象,在这里我模拟了一个异步对象在线程里做一些耗时操作如下。
public class DelayTask {
public int _seconds { get; set; }
public DelayTask(int seconds) {
_seconds = seconds;
}
public IAsyncResult BeginDelay(AsyncCallback callback,object state) {
var result = new DelayTaskAsyncResult(callback,state);
ThreadPool.QueueUserWorkItem(_delayCore, result);
return result;
}
public object EndDelay(IAsyncResult asyncResult) {
var result = (DelayTaskAsyncResult)asyncResult;
return result.EndInvoke();
}
private void _delayCore(object obj) {
var asyncResult = (DelayTaskAsyncResult)obj;
Thread.Sleep(_seconds * 1000);
asyncResult.result = DateTime.Now;
asyncResult.SetCompleted();
}
}
在DelayTask里,BeginDelay接受两个参数AsyncCallback和object,这两个参数是为了回调机制使用的,然后创建一个异步结果DelayTaskAsyncResult传入另一个线程执行_delayCore,在_delayCore执行一个耗时操作然后将结果赋予result对象并更新状态SetCompleted,在EndDelay里,调用EndInvoke去同步异步结果。
使用方式如下
public static void Main(string[] args) {
DelayTask task = new DelayTask(5);
var asyncResult = task.BeginDelay(null, null);
Console.WriteLine("main execute");
Console.WriteLine("other end at " + task.EndDelay(asyncResult));
Console.Read();
}
//execute result:
//main execute
//consume time operation
//other end at 2021/6/3 20:51:18
这个实现了异步操作并没有block main thread,直到调用EndDelay block得到执行结果。下一步再看一下异步回调方法的使用。
public static void Main(string[] args) {
DelayTask task = new DelayTask(5);
var asyncResult = task.BeginDelay(TaskCompleteCallBack, task);
Console.WriteLine("main execute");
Console.Read();
}
private static void TaskCompleteCallBack(IAsyncResult ar) {
var task = (DelayTask)ar.AsyncState;
Console.WriteLine("other end at " + task.EndDelay(ar));
}
效果和上面一样,值得注意的是异步的时候回调方法是执行在另一个线程上。 好了,APM的模式实现我们已经完成了。
现在我们看第二种的EAP的实现方式,基于事件的异步编程模式。这在富客户端应用程序大展拳脚。他的实现非常简单。
public delegate void TaskCompletedEventHandler(object sender, TaskCompletedEventArg e);
public class DelayTask1 {
private int _seronds;
public DelayTask1(int seronds) {
_seronds = seronds;
}
public event TaskCompletedEventHandler TaskCompletedEventHandler;
public void DoTaskAsync(string str) {
ThreadPool.QueueUserWorkItem(TaskHelper,str);
}
private void TaskHelper(object state) {
var text = (string)state;
Thread.Sleep(_seronds*1000);
var result = DateTime.Now.ToString("yyyy-mm-dd")+text;
TaskCompletedEventHandler.Invoke(this,new TaskCompletedEventArg {
Result= result
});
}
}
首先定义一个委托,然后用这个委托声明事件,委托定义了一个事件参数是为了回调使用,然后TaskHelper就是异步执行的方法,基于事件的实现因为没有异步对象IAsyncResult实现的非常清晰。调用如下。
public static void Main(string[] args) {
var task = new DelayTask1(5);
task.TaskCompletedEventHandler += TaskCompleteCallBack;
task.DoTaskAsync(" by neil");
Console.WriteLine("main execute");
Console.Read();
}
private static void TaskCompleteCallBack(object sender, TaskCompletedEventArg e) {
Console.WriteLine("other end at"+ e.Result);
}
//main execute
//consume time operation
//other end at2021-11-03 by neil
EAP模式的例子非常清晰,大家可以运行就可。
现在我们使用第三种的TAP的异步编程模型非常多,不管是富客户端还是asp.net core中,这是因为编译器在中间做了大量的工作,async和await关键字会将代码分为同步和回调,这个模式的实现还是需要反编译源码去知道编译器做了哪些动作。以后有时间我会和大家探讨一下这其中的原理。
好了今天就写到这里了,如果大家有任何不明白的地方欢迎评论留言,最后谢谢大家的阅读。
.Net Core自实现CLR异步编程模式(Asynchronous programming patterns)的更多相关文章
- C#的多线程——使用async和await来完成异步编程(Asynchronous Programming with async and await)
https://msdn.microsoft.com/zh-cn/library/mt674882.aspx 侵删 更新于:2015年6月20日 欲获得最新的Visual Studio 2017 RC ...
- 游戏编程模式 Game Programming Patterns (Robert Nystrom 著)
第1篇 概述 第1章 架构,性能和游戏 (已看) 第2篇 再探设计模式 第2章 命令模式 (已看) 第3章 享元模式 (已看) 第4章 观察者模式 (已看) 第5章 原型模式 (已看) 第6章 单例模 ...
- C#多线程和异步(三)——一些异步编程模式
一.任务并行库 任务并行库(Task Parallel Library)是BCL中的一个类库,极大地简化了并行编程,Parallel常用的方法有For/ForEach/Invoke三个静态方法.在C# ...
- .NET “底层”异步编程模式——异步编程模型(Asynchronous Programming Model,APM)
本文内容 异步编程类型 异步编程模型(APM) 参考资料 首先澄清,异步编程模式(Asynchronous Programming Patterns)与异步编程模型(Asynchronous Prog ...
- C#中的异步编程模式
异步编程模型(APM) 基于事件的异步编程模式 基于任务的异步模式 Async Await编程 关于C#,可以看看Learning Hard的博客
- 二、基于事件的异步编程模式(EAP)
一.引言 在上一个专题中为大家介绍了.NET 1.0中提出来的异步编程模式--APM,虽然APM为我们实现异步编程提供了一定的支持,同时它也存在着一些明显的问题--不支持对异步操作的取消和没有提供对进 ...
- 基于任务的异步编程模式,Task-based Asynchronous Pattern
术语: APM 异步编程模型,Asynchronous Programming Model,其中异步操作由一对 Begin/End 方法(如 FileStream.BeginRea ...
- [.net 多线程]异步编程模式
.NET中的异步编程 - EAP/APM 从.NET 4.5开始,支持的三种异步编程模式: 基于事件的异步编程设计模式 (EAP,Event-based Asynchronous Pattern) 异 ...
- 基于任务的异步编程模式(TAP)的错误处理
在前面讲到了<基于任务的异步编程模式(TAP)>,但是如果调用异步方法,没有等待,那么调用异步方法的线程中使用传统的try/catch块是不能捕获到异步方法中的异常.因为在异步方法执行出现 ...
随机推荐
- hdu2962 二分 + spfa
题意: 给你一个无向图,每条路径上都有自己的长度和最大承受高度,给你起点终点还有车的最大承装高度,问你高度最大的前提下路径最短是多少,求高度和路径. 思路: 这种类型题目太多了, ...
- hdu5062 简单题
题意: 求区间逆序数的个数,逆序数增加了个要求就是必须要是先升序在降序例如12321或者123321这样的. 思路: 水题直接写就行了,数据范围不大,估计直接求也不会超时,我 ...
- Linux下的用户、组和权限
目录 一:用户和组信息的查看 查看用户信息 查看密码信息 查看组信息 特殊组wheel 二:用户和组信息的管理 用户管理 组管理 三:文件权限 文件权限的查看 文件权限的修改 ACL控制权限 setf ...
- Portswigger web security academy:Server-side template injection(SSTI)
Portswigger web security academy:Server-side template injection(SSTI) 目录 Portswigger web security ac ...
- Spring SPI 机制总结
1.概念: SPI(Service Provider Interface)服务提供接口,简单来说就是用来解耦,实现插件的自由插拔,具体实现方案可参考JDK里的ServiceLoader(加载class ...
- 【python】Leetcode每日一题-扁平化嵌套列表迭代器
[python]Leetcode每日一题-扁平化嵌套列表迭代器 [题目描述] 给你一个嵌套的整型列表.请你设计一个迭代器,使其能够遍历这个整型列表中的所有整数. 列表中的每一项或者为一个整数,或者是另 ...
- Pytorch系列:(五)CNN
卷积 Conv2d 2D卷积函数和参数如下 nn.Conv2d( in_channels, out_channels, kernel_size, stride=1, padding=0, dilati ...
- 四种方式带你层层递进解剖算法---hash表不一定适合寻找重复数据
一.题目描述 找出数组中重复的数字 > 在一个长度为 n 的数组 nums 里的所有数字都在 0-n-1 的范围内.数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次. ...
- laravel 伪静态实现
Route::get('show{id}.html',['as'=>'products.detail','uses'=>'companyController@show']) ->wh ...
- 基础知识:DFRduino UNO R3最全资料详解
一.概述篇:1. 什么是DFRduino UNO R3?DFRduino UNO R3是一块基与开放原始代码的Simple i/o平台,並且具有使用类似java,C语言的开发环境.让您可以快速使用Ar ...