.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块是不能捕获到异步方法中的异常.因为在异步方法执行出现 ...
随机推荐
- Ducci Sequence UVA - 1594
A Ducci sequence is a sequence of n-tuples of integers. Given an n-tuple of integers (a1,a2,···,an ...
- Java整合极光推送 ( 简单 )
Java 整合极光推送官方文档:https://github.com/jpush/jpush-api-java-client 这里记录一下简单的使用步骤:创建一个普通的 Maven 工程然后添加依赖 ...
- 1019 General Palindromic Number
A number that will be the same when it is written forwards or backwards is known as a Palindromic Nu ...
- 1067 Sort with Swap(0, i)
Given any permutation of the numbers {0, 1, 2,..., N−1}, it is easy to sort them in increasing order ...
- 473. Matchsticks to Square
Remember the story of Little Match Girl? By now, you know exactly what matchsticks the little match ...
- 『动善时』JMeter基础 — 3、JMeter插件管理
JMeter是一个Java开发的开源软件,开源的软件有一个好处,就是会有很多第三方开发出来的插件,使得JMeter在处理某一些功能的时候更加的方便.并且这些插件拿过来就可以使用,完全免费的. 我们安装 ...
- css单位介绍em ex ch rem vw vh vm cm mm in pt pc px
长度单位主要有以下几种em ex ch rem vw vh vm cm mm in pt pc px %,大概可以分为几种"绝对单位"和"相对单位"和" ...
- 【Springboot项目启动异常】项目启动,数据库连接异常
今天使用Springboot 整合 MybatisPlus 准备写一个Demo,在项目启动时,频繁出错,在此记录整个问题的解决过程 问题如下图 人工翻译一遍,主要意思就是没有检测到数据库驱动,也就是说 ...
- 百度sitemap.xml
<?xml version="1.0" encoding="UTF-8" ?> <urlset xmlns="http://www. ...
- 路由器逆向分析------MIPS交叉编译环境的搭建(Buildroot)
本文博客地址:http://blog.csdn.net/qq1084283172/article/details/68950682 为了能在我们熟悉的windows或者ubuntu下开发mips架构的 ...