Reactor模式的.net版本简单实现

     近期在学习DotNetty,遇到不少的问题。由于dotnetty是次netty的.net版本的实现。导致在网上叙述dotnetty的原理,以及实现技巧方面的东西较少,这还是十分恼人的。在此建议学习和使用Dotnetty的和位小伙伴,真心阅读下netty的相关书籍,如《netty权威指南》。

     闲话少说,进入正题。netty的性能之所以能够达到如此的高度。主要由于他使用Reactor模式处理socket的请求,让服务器的使用率最大化,且尽量减少线程的开销。本文章主要简单介绍下Reactor模式。

一、reactor概论

reactor模式主要解决处理多个客户端请求的设计模式。

首先从类图我们可以得知:

Dispatcher:Handler管理器,以及调用度。他依赖于Demultiplexer类

Demultiplexer:事件管理器,接受外部的事件,并提供给Dispatch使用。

Handle:事件源,表示触发了那些事件

EventHandler:各种类型的处理器,用于处理具体的业务,以及I/O的读写

当然,也可以通过序列图看出首先需要初始化Dispatcher, Demultiplexer等相关类,以及注册具体的事件处理器。

二、代码的具体实现

类图如下[源码下载]:

2.1 多路复用事件处理器的代码

1public class Demultiplexer 2 { 3 private ConcurrentQueue<Event> eventQuene = new ConcurrentQueue<Event>(); 4 private Object lockObj = new Object(); 5 6 public List<Event> Select() 7 { 8 return this.Select(0); 9 } 10 public List<Event> Select(int time) 11 { 12 if(time > 0) 13 { 14 if (this.eventQuene.IsEmpty) 15 { 16 lock (lockObj) 17 { 18 if (this.eventQuene.IsEmpty) 19 { 20 System.Threading.Thread.Sleep(time); 21 } 22 } 23 } 24 } 25 List<Event> events = new List<Event>(); 26 while(this.eventQuene.Count > 0) 27 { 28 Event tmp; 29 if(this.eventQuene.TryDequeue(out tmp)) 30 { 31 events.Add(tmp); 32 } 33 } 34 return events; 35 } 36 public void AddEvent(Event argEvent) 37 { 38 this.eventQuene.Enqueue(argEvent); 39 } 40 }

此类主要防止多线程的共同竞争,因为多路径复用选择器会被多个线程同时使用。所以使用的线程安全的Queue。

2.2 Handler触发器和管理器

1/// <summary> 2 /// Reactor的事件Handler触发器,提供事件Handler的注册,移除 3 /// </summary> 4 public class EventDispatch 5 { 6 private Demultiplexer demultiplexer; 7 Dictionary<EventType, EventHandler> eventHandlerMap = new Dictionary<EventType, EventHandler>(); 8 9 public EventDispatch(Demultiplexer demultiplexer) 10 { 11 this.demultiplexer = demultiplexer; 12 } 13 14 public void RegisterHandler(EventType eventType, EventHandler eventHandler) 15 { 16 this.eventHandlerMap.Add(eventType, eventHandler); 17 } 18 public void RemoveHandler(EventType eventType) 19 { 20 this.eventHandlerMap.Remove(eventType); 21 } 22 23 public void HandleEvents() 24 { 25 this.Dispatch(); 26 } 27 public void Dispatch() 28 { 29 string log = string.Format("thread id: {0} Dispatch", System.Threading.Thread.CurrentThread.ManagedThreadId); 30 Console.WriteLine(log); 31 while (true) 32 { 33 List<Event> events = this.demultiplexer.Select(); 34 foreach(var itemEvent in events) 35 { 36 EventHandler eventHandler = this.eventHandlerMap[itemEvent.EventType]; 37 eventHandler.Handle(itemEvent); 38 } 39 System.Threading.Thread.Sleep(1000); 40 } 41 } 42 }

主要职责,对Handler的注册、移除的管理,以及通过 多路复用选择器 选择相应的Handler进行处理。

2.3 服务端的实现

1/// <summary> 2 /// 开启接受请求的服务端 3 /// </summary> 4 public class AcceptRuner 5 { 6 private System.Collections.Concurrent.ConcurrentQueue<object> sourceQueue = new System.Collections.Concurrent.ConcurrentQueue<object>(); 7 8 private Demultiplexer demultiplexer; 9 10 public AcceptRuner(Demultiplexer demultiplexer) 11 { 12 this.demultiplexer = demultiplexer; 13 } 14 15 public void adConnection(object source) 16 { 17 this.sourceQueue.Enqueue(source); 18 } 19 20 public void Run() 21 { 22 string log = string.Format("thread id: {0} AcceptRunner", System.Threading.Thread.CurrentThread.ManagedThreadId); 23 Console.WriteLine(log); 24 while (true) 25 { 26 object source; 27 if(this.sourceQueue.TryDequeue(out source)) 28 { 29 Event acceptEvent = new Event() 30 { 31 EventType = EventType.Accept, 32 Source = source 33 }; 34 this.demultiplexer.AddEvent(acceptEvent); 35 } 36 } 37 } 38 }

此类效仿netty的serverBoostrap的实现,将外部新的连接以事件对象的形式添加到 多路复用选择器上。

2.4 其他类

Event:事件基类

EventHandler:事件处理器抽象基类。他派生了:AcceptEventHandler,ReadEventHandler。

EventType:事件类型

三、备注说明

1. 代码没有贴完整。但下载包就是完整的。

2. 这只我对Reactor模式的理解,如有偏颇之处,还望各拉指点一二。

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )

SpringBoot整合Redis乱码原因及解决方案

问题描述:springboot使用springdataredis存储数据时乱码rediskey/value出现\\xAC\\xED\\x00\\x05t\\x00\\x05问题分析:查看RedisTemplate类!(https://oscimg.oschina.net/oscnet/0a85565fa

Android So动态加载 优雅实现与原理分析

背景:漫品Android客户端集成适配转换功能(基于目标识别(So库35M)和人脸识别库(5M)),导致apk体积50M左右,为优化客户端体验,决定实现So文件动态加载.!(https://oscimg.oschina.net/oscnet/00d1ff90e4b34869664fef59e3ec3fdd20b.png)点击上方“蓝字”关注我

Reactor模式的.net版本简单实现 - HelloWorld