为了可以更灵活地在Webapi应用服务中分配线程资源,BeetleX.FastHttpApi在线程调度上直接细化到Action级别;组件不仅可以精准控制每个Action的最大RPS限制,还能精细到控制使用多少线程资源来处理这些API的请求。接下来详细讲解组件针对这一块的实现结构和代码。

需求

为什么要做到这么精细的控制呢?如果有足够资源那是不用考虑这方面的问题;但实际应用中资源不足是经常需要面对的问题。在整个服务中往往有些API非常占用资源,这个时候就希望通过简单配置来控制API使用的线程数达到一个理想的资源分配结果。在控制上最直接的办法是控制对应的RPS数量,但有时候希望以线程资源的方式来分配。

使用

组件可以在控制器的Action上根据需求标记对应的限制属性

        //每秒最大处理数100,超过就拒绝[RequestMaxRPS(100)]public object MasRps(IHttpContext context){return DateTime.Now;}//不限制,由框架通过线程池调度public object None(string name, IHttpContext context){return $"Name:{name}|QueueID:{context.Queue?.ID}|Time:{DateTime.Now}";}//所有请求用一个线程有序处理[ThreadQueue(ThreadQueueType.Single)]public object SingleQueue(string name, IHttpContext context){return $"Name:{name}|QueueID:{context.Queue?.ID}|Time:{DateTime.Now}";}//所有请求分配两个线程有序处理[ThreadQueue(ThreadQueueType.Multiple, 2)]public object MultipleQueue(string name, IHttpContext context){return $"Name:{name}|QueueID:{context.Queue?.ID}|Time:{DateTime.Now}";}//根据Name的值一致线程处理,同一值会分配到一个线程中有序处理[ThreadQueue("name")]public object UniqueQueue(string name, IHttpContext context){return $"Name:{name}|QueueID:{context.Queue?.ID}|Time:{DateTime.Now}";}

设计实现

接下来看一下BeetleX.FastHttpApi组件代码是如何进行工作的。由于需要线程控制,那自然就需要一个队列;组件提供一个NextQueue的队列来完成这方面的工作,每个NextQueue会分配一个线程来处理。

   public class NextQueue : IDisposable{public NextQueue(){mQueue = new System.Collections.Concurrent.ConcurrentQueue<IEventWork>();ID = System.Threading.Interlocked.Increment(ref mID);}public long ID { get; set; }private static long mID;private readonly object _workSync = new object();private bool _doingWork;private int mCount;private System.Collections.Concurrent.ConcurrentQueue<IEventWork> mQueue;public int Count => mCount;//添加任务到队列中public void Enqueue(IEventWork item){mQueue.Enqueue(item);System.Threading.Interlocked.Increment(ref mCount);lock (_workSync){//当前队列是否工作中if (!_doingWork){//获取一个线程进行工作System.Threading.ThreadPool.QueueUserWorkItem(OnStart);_doingWork = true;}}}private void OnError(Exception e, IEventWork work){try{Error?.Invoke(e, work);}catch{}}public static Action<Exception, IEventWork> Error { get; set; }private async void OnStart(object state){while (true){//获取队列任务并执行while (mQueue.TryDequeue(out IEventWork item)){System.Threading.Interlocked.Decrement(ref mCount);using (item){try{//等待任务执行await item.Execute();}catch (Exception e_){OnError(e_, item);}}}lock (_workSync){//队列为空跑出线程if (mQueue.IsEmpty){try{Unused?.Invoke();}catch { }_doingWork = false;return;}}}}public Action Unused { get; set; }public void Dispose(){while (mQueue.TryDequeue(out IEventWork work)){try{work.Dispose();}catch{}}}}

NextQueue是一个支持异步任务的处理队列,它确保添加进来的任务都是有序执行,即使任务内部处理的任务是异步。

ActionContext

该对象是用于执行控制器方法,包括webapi控制器和Websocket控制器。在这里只讲述控制怎样调度执行的,更详细了解可以查看

https://github.com/beetlex-io/FastHttpApi/blob/master/src/ActionContext.cs

主要讲解一下Execute方法是怎样调用控制器方法的

        internal async Task Execute(IActionResultHandler resultHandler){//验证RPSif (Handler.ValidateRPS()){Handler.IncrementRequest();//是否存在队列控制配置if (Handler.ThreadQueue == null || Handler.ThreadQueue.Type == ThreadQueueType.None){if (Handler.Async)//异步方法{await OnAsyncExecute(resultHandler);}else{//同步方法OnExecute(resultHandler);}}else{//配置了队列控制r妊ActionTask actionTask = new ActionTask(this, resultHandler,new TaskCompletionSource<object>());//获取异步队列var queue = Handler.ThreadQueue.GetQueue(this.HttpContext);//阶列是否有效,为了安全队列都有最大等待数限制,超过就拒绝处理if (Handler.ThreadQueue.Enabled(queue)){this.HttpContext.Queue = queue;//把当前任务插入队列queue.Enqueue(actionTask);//等待队执行结果通知await actionTask.CompletionSource.Task;}else{Handler.IncrementError();resultHandler.Error(new Exception($"{Handler.SourceUrl} process error,out of queue limit!"), EventArgs.LogType.Warring, 500);}}}else{Handler.IncrementError();resultHandler.Error(new Exception($"{Handler.SourceUrl} process error,out of max rps!"), EventArgs.LogType.Warring, 509);}}

GetQueue

应该方法根据当前请示信息和配置来获取对应的异步队列

        public NextQueue GetQueue(IHttpContext context){//单队执行,永远返回针对当前控制器方法的第一个队列if (Type == ThreadQueueType.Single)return QueueGroup.Queues[0];//轮循当前分配最大队列数else if (Type == ThreadQueueType.Multiple)return QueueGroup.Next();//针对请求数据做一致性队列分配else if (Type == ThreadQueueType.DataUnique){string value = null;if (UniqueName != null){if (string.Compare(UniqueName, "$path", true) == 0){value = context.Request.GetSourcePath();}else if(UniqueName.IndexOf("__")==0){return mUniqueQueueGroup.Has(UniqueName.GetHashCode());}else{value = context.Request.Header[UniqueName];if (value == null)context.Data.TryGetString(UniqueName, out value);}}if (value == null)value = context.Request.GetSourceUrl();return mUniqueQueueGroup.Has(value.GetHashCode());}//如果都没匹配到就获取轮循的下一个return QueueGroup.Next();}

ActionTask

方法异步任务对象,队列会有序地执行相关对象,这对象的实现非常简单。

        struct ActionTask : IEventWork{public ActionTask(ActionContext context, IActionResultHandler resultHandler, TaskCompletionSource<object> completionSource){Context = context;ResultHandler = resultHandler;CompletionSource = completionSource;}public TaskCompletionSource<object> CompletionSource { get; set; }public ActionContext Context { get; set; }public IActionResultHandler ResultHandler { get; set; }public void Dispose(){}public async Task Execute(){try{if (Context.Handler.Async){//异步方法await Context.OnAsyncExecute(ResultHandler);}else{//同步方法Context.OnExecute(ResultHandler);}}finally{//回调执行完成,让队列继续下一个任务。CompletionSource?.TrySetResult(new object());}}}

总结

到这里整个线程调度的核心就介绍完成了,如果不了解一些基础知识会感觉完成这些功能很复杂,其实都是一些基础功能的应用; 完成这些功能主要涉及几个基础知识分别是:队列,线程池和用于处理异步回调的TaskCompletionSource对象。

BeetleX

开源跨平台通讯框架(支持TLS)
提供高性能服务和大数据处理解决方案

https://beetlex.io

BeetleX.FastHttpApi之控制器调度设计相关推荐

  1. BeetleX.FastHttpApi之Vuejs扩展

    非常喜欢用vuejs,但又不想花时间去搞nodejs和webpack之类的,所以才有了BeetleX.FastHttpApi.VueExtend这样一个组件:组件的主要功能就是可以实现在vs.net中 ...

  2. BeetleX.FastHttpApi之JWT和自定义访问验证

    BeetleX.FastHttpApi.Jwt组件是BeetleX.FastHttpApi的JWT安全验证插件,通组件的简单配置即可以实现对webapi进行安全访问控制.接下来介绍如何使用这组件并和其 ...

  3. 基于FPGA的CAN总线控制器的设计(下)

    今天给大侠带来基于FPGA的CAN总线控制器的设计,由于篇幅较长,分三篇.今天带来第三篇,下篇,程序的仿真与测试以及总结.话不多说,上货. 导读 CAN 总线(Controller Area Netw ...

  4. 基于FPGA的CAN总线控制器的设计(上)

    今天给大侠带来基于FPGA的CAN总线控制器的设计,由于篇幅较长,分三篇.今天带来第一篇,上篇,CAN 总线协议解析以及 CAN 通信控制器程序基本框架.话不多说,上货. 导读 CAN 总线(Cont ...

  5. MATLAB中PI调节器设计,华中科技大学电气学院matlab选修课大作业pi控制器的设计...

    华中科技大学电气学院matlab选修课大作业pi控制器的设计 2008 级<MATAB 语言与控制系统仿真>课程大作业姓 名 赖智鹏 学 号 u200811806 所在院系 电气与电子工程 ...

  6. 2016计算机课程设计,2016年计算机组成原理课程设计-硬布线控制器的设计.doc

    2016年计算机组成原理课程设计-硬布线控制器的设计 编 号: 学 号: 课 程 设 计 教 学 院计算机学院课程名称计算机组成原理课程设计题 目硬布线控制器的设计专 业计算机科学与技术班 级二班姓 ...

  7. VHDL交通灯控制器的设计

    主要内容: 设计主干道的交叉路口交通信号灯无人自动管理的控制系统.将路口红绿灯的各种亮灯情况定义不同的状态,路口状况定义为触发条件,组成有限状态机. 1.设计的目的 本次课程设计的目的是通过设计交通灯 ...

  8. (转)基于MVC4+EasyUI的Web开发框架形成之旅--MVC控制器的设计

    http://www.cnblogs.com/wuhuacong/p/3284628.html 自从上篇<基于MVC4+EasyUI的Web开发框架形成之旅--总体介绍>总体性的概括,得到 ...

  9. 模型计算机控制器的设计,模型计算机控制器的设计.pdf

    第 0 页模型计算机控制器的设计 <计算机组成原理> 课 程 设 计 报 告 设计题目 : 模型计算机控制器的设计 学 生: 学 号: 专业班级: 13 计师 X 班 指导教师: 麦 山 ...

最新文章

  1. c语言关闭其他进程tcp_tcp链接迁移
  2. python与MySQL交互
  3. java 内存 开发 经验_有一到五年开发经验的JAVA程序员需要掌握的知识与技能!...
  4. 微软Windows Server 2008认证体系详细介绍
  5. pku1067----取石子游戏(博弈)
  6. 程序员该不该主动提加薪?| 畅言
  7. Spring IOC中bean标签和管理对象细节
  8. CE修改植物大战僵尸
  9. etcd教程(二)—clientv3简单使用
  10. 自增主键的sql设置语句
  11. Cannot load C:\Users\12778\AppData\Local\JetBrains\IntelliJIdea2021.1\tomcat\c0cf5d96-4221-48ee-b343
  12. 第三天---随机小方块
  13. 操作系统概念v9 Abraham Silberschatz 全文笔记
  14. 确定有限自动机(DFA)和不确定有限自动机(NFA)的主要区别
  15. 100个python算法超详细讲解:存钱
  16. linux 下中文字体的支持
  17. InfiniBand架构和技术实战总结
  18. 计算机上电自检的作用,电脑每次开机都自检的几种解决方法
  19. <Java>根据身高体重计算BMI指数
  20. uniapp免费视频教程

热门文章

  1. 开始→运行→命令 总结大全
  2. 好用的shell工具_精选5个酷毙的Python工具
  3. jQuery 1.9+ 移除$.browser方法
  4. pl/sql查询表数据,报错ORA-03115:不支持的网络数据类型或表示法
  5. supervisord的安装使用
  6. java数组转list(Arrays .asList)
  7. 解决java.lang.NoClassDefFoundError: org/aopalliance/intercept/MethodInterceptor问题
  8. BFS HDOJ 2102 A计划
  9. android 游戏 重力
  10. 在DataGrid中合并单元格行