.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块是不能捕获到异步方法中的异常.因为在异步方法执行出现 ...
随机推荐
- JAVAEE_Servlet_06_ServletContext接口
ServletContext接口 * javax.servlet.ServletContext * Tomcat服务器中ServletContecxt的完整类名: ServletContext:org ...
- Day03_16_递归
Java递归 递归包含两个部分 递归头: 标明了什么时候结束递归调用,如果没有递归头,程序将陷入死循环. 递归体: 标明了什么时候需要继续调用自身. 实例 import java.util.Scann ...
- 【Spring】循环依赖
@ 目录 循环依赖 是什么? Spring是如何解决的? 源码分析 细节 循环依赖 是什么? 简单的来说就是对象a的属性中引用了对象b,对象b的属性中引用了对象c......最后引用到a. < ...
- 面试系列<5>——面向对象
面试系列--面向对象思想 一.三大特性 封装 利用抽象数据类型将数据和基于数据的操作封装在一起,使其成为一个不可分割的独立实体.数据被保护在抽象数据类型内部,尽可能地隐藏内部细节,只保留一些对外的接口 ...
- java面试一日一题:讲下redo log
问题:请讲下redo log的作用 分析:mysql中有很多日志,例,binlog undo log redo log,要弄清楚这些日志的作用,就要了解这些日志出现的背景及要解决的问题? 回答要点: ...
- 判断post,ajax,get请求的方法
判断post,ajax,get请求的方法 define('IS_GET',isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] ...
- hdu4280 最大流DINIC
题意: x最小的到x最大的点同一时间的最大运输量. 思路: 裸的最大流,不解释,注意一点,记得加上防爆栈. #pragma comment(linker, "/STA ...
- IIS7.5配置对PHP的支持
以下环境是 Windows server2008R2 IIS7.5 一般情况下,windows server系统默认是仅支持IIS+asp 或 IIS+aspx 的 搭配的,但是有时候我们的网站程序是 ...
- PowerShell-4.API调用以及DLL调用
PowerShell可以直接调用API,So...这东西完全和cmd不是一回事了... 调用API的时候几乎和C#一样(注意堆栈平衡): 调用MessageBox: $iii = Add-Type - ...
- Error starting userland proxy: /forwards/expose/port returned unexpected status: 500.
欢迎关注微信公众号 Error starting userland proxy: /forwards/expose/port returned unexpected status: 500. dock ...