.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块是不能捕获到异步方法中的异常.因为在异步方法执行出现 ...
随机推荐
- 前端进阶(2)使用fetch/axios时, 如何取消http请求
前端进阶(2)使用fetch/axios时, 如何取消http请求 1. 需求 现在前端都是SPA,我们什么时候需要取消HTTP请求呢? 当我们从一个页面跳转到另外一个页面时,如果前一个页面的请求还没 ...
- 14.Quick QML-TextInput详解
1.TextInput属性用来编辑一行文本,对应QLineEdit,除了正常输入外,我们还可以设置echoMode属性改为密码显示状态,也可以通过validator属性和inputMask属性来设置验 ...
- 微服务的进程间通信(IPC)
微服务的进程间通信(IPC) 目录 微服务的进程间通信(IPC) 术语 概述 通信视角 APIs 消息格式 RPC REST gRPC 断路器 API通信的健壮性 服务发现 异步消息 概念 消息 消息 ...
- k8s新手必看
转载自https://juejin.im/post/6844903840139968520 Kubernetes零基础快速入门!初学者必看! 起源 Kubernetes 源自于 google 内部的服 ...
- ajax--实现异步请求,接受响应及执行回调
ajax最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页的内容 ajax指是一种创建交互式网页应用的网页开发技术,其实就是实现前后端交互. 1)ajax是异步javascr ...
- Java IO流知识总结
Java IO的原理 I/O是Input和Output的缩写,用来处理设备之间的数据传输.如读/写文件,网络通讯等. Java程序中,对于数据的输入/输出操作以"流(stream)" ...
- Windows PE 第十二章 PE变形技术
PE变形技术 这章东西太多,太细了.这里我只记录了一些重点概念.为后面学习做铺垫. PE变形:改变PE结构之后,PE加载器依然可以成功加载运行我们的程序. 一 变形常用技术: 结构重叠技术.空间调整技 ...
- c# 通过 p/invoke 使用 c的加密程序 参数传递问题
最近项目中使用需要上位机和下位机通过rs232通信,涉及到通讯加密问题, 硬件那边主要是pcb layout的,于是我就把加密的活拦了过来,锻炼锻炼 首先说明问题: 在c中,加密解密都测试通过,然后在 ...
- Docker+Nginx配置SSL
参考阿里云文档教程 前提条件 购买服务器的服务商开启443端口和服务器已开启443端口(https的默认端口) nginx容器已经安装http_ssl_module模块(启用SSL功能) 下面的教程基 ...
- linux集群压测部署方案
我们今天主要分享的内容从三方面讲解. 集群压力机部署 shell脚本简介 shell脚本搞定压力机部署 集群压力机部署 linux.png 分布式压测背景介绍 在企业项目实战时,如果被压的服务器处 ...