BeetleX.FastHttpApi之控制器调度设计

    为了可以更灵活地在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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/302339.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java类加载机制深度分析

为什么80%的码农都做不了架构师&#xff1f;>>> Java类加载机制 类加载是Java程序运行的第一步&#xff0c;研究类的加载有助于了解JVM执行过程&#xff0c;并指导开发者采取更有效的措施配合程序执行。研究类加载机制的第二个目的是让程序能动态的控制类加载&…

北大清华团队编写!200多个科学实验+视频,和爸爸一起在家做

自从2017年2月份教育部从小学一年级起将科学课列入必修课&#xff0c;学校、家长都意识到科学素养对于孩子成长的重要性。好多家长都跃跃欲试&#xff0c;想陪孩子把科学“玩”起来。可是具体到如何给孩子做科学启蒙&#xff0c;面对的问题还真不少&#xff1a;生活中有哪些科学…

如何搭建一个指标体系

2019独角兽企业重金招聘Python工程师标准>>> 今天跟大家聊聊&#xff0c;如何搭建一个指标体系。 1、什么是指标体系 “指标体系”这个概念是应用比较广泛的&#xff0c;我们从正式出版物中摘取一个定义&#xff1a; 指标体系&#xff0c;即统计指标体系&#xff0c…

2018年最后一个月最值得关注的13个优质公号

全世界有3.14 % 的人已经关注了数据与算法之美在这个知识千变万化的时代只有不断学习、充实自我&#xff0c;才能跟上时代以下13个顶级公众号能让你扩宽视野&#xff0c;紧跟时代的潮流近现代史研究通讯ID&#xff1a;jxsdyjtx2015▲长按二维码“识别”关注设置为星标近现代史研…

.NET Worker Service 如何优雅退出

上一篇文章中我们了解了 .NET Worker Service 的入门知识[1]&#xff0c;今天我们接着介绍一下如何优雅地关闭和退出 Worker Service。Worker 类从上一篇文章中&#xff0c;我们已经知道了 Worker Service 模板为我们提供三个开箱即用的核心文件&#xff0c;其中 Worker 类是继…

大数据告诉你,中国女人有多勤奋

全世界只有3.14 % 的人关注了数据与算法之美前段时间&#xff0c;美国国家统计局发布了一组关于世界各国劳动参与率的数据&#xff0c;中国赫然位列世界第一&#xff0c;劳动总量世界第一&#xff0c;劳动参与率世界第一。所谓劳动总量&#xff0c;就是所有工作的人的工作时间的…

get+php+mysql_Apache+PHP+MySql 的安装及配置

每一项技术用的人多了&#xff0c;就会有人将其进行优化&#xff0c;做成一个简单、实用、大众化的工具&#xff0c;这对于初识者来说是非常方便的&#xff0c;但是对于长久学习或工作这方面的人技术人员来说是不可取的&#xff0c;所以还是要学习基础的实用方法。因此&#xf…

记一次 .NET 车联网云端服务 CPU爆高分析

一&#xff1a;背景 1. 讲故事前几天有位朋友wx求助&#xff0c;它的程序CPU经常飙满&#xff0c;没找到原因&#xff0c;希望帮忙看一下。这些天连续接到几个cpu爆高的dump&#xff0c;都看烦了????????????&#xff0c;希望后面再来几个其他方面的dump&#xff0…

java swing 示例_JAVA简单Swing图形界面应用演示样例

JAVA简单Swing图形界面应用演示样例package org.rui.hello;import javax.swing.JFrame;/*** 简单的swing窗体* author lenovo**/public class HelloSwing {public static void main(String[] args) {JFrame framenew JFrame("hello Swing");frame.setDefaultCloseOpe…

.NET上海社区线下Meetup - 5.22 Blazor Day

Blazor 是一个 Web UI 框架&#xff0c;Blazor 旨在简化快速的单页面 .Net 浏览器应用的构建过程&#xff0c;它虽然使用了诸如 CSS 和 HTML 之类的 Web 技术&#xff0c;但它使用 C&#xff03;语言和 Razor 语法代替 JavaScript 来构建可组合的 Web UI 。通过提供用于编译到 …

入门机器学习,开启人工智能大门!

AI这个词相信大家都非常熟悉&#xff0c;近几年来人工智能圈子格外热闹&#xff0c;光是AlphoGo就让大家对它刮目相看。今天小天就来跟大家唠一唠如何进军人工智能的第一步——机器学习。在机器学习领域&#xff0c;Python已经成为了主流。一方面因为这门语言简单易上手&#x…

java集合框架的结构_集合框架(Collections Framework)详解及代码示例

简介集合和数组的区别&#xff1a;数组存储基础数据类型&#xff0c;且每一个数组都只能存储一种数据类型的数据&#xff0c;空间不可变。集合存储对象&#xff0c;一个集合中可以存储多种类型的对象。空间可变。严格地说&#xff0c;集合是存储对象的引用&#xff0c;每个对象…

Unity3D OpenVR 虚拟现实 保龄球打砖块游戏开发

据说水哥买了 Valve Index 设备&#xff0c;既然这个设备这么贵&#xff0c;不开发点有&#xff08;zhi&#xff09;趣&#xff08;zhang&#xff09;游戏就感觉对不起这个设备。本文将来开始着手开发一个可玩性不大&#xff0c;观赏性极强的保龄球打砖块游戏。这仅仅只是一个入…

mac mysql 移动硬盘_MAC一些高能过程记录(一些没必要的坑)

搞计算机的&#xff0c;谁电脑上没个数据库&#xff0c;不管用不用的着&#xff0c;有时候总需要&#xff0c;比如调试下博客呀之类的, 毕竟一般都会觉得数据库很好玩啊1.MySql安装&#xff1a;dmg、pkg什么的直接装吧&#xff0c;结束后会给你一个提示&#xff0c;上面会有密…

数学思维比数学运算更重要

全世界只有3.14 % 的人关注了数据与算法之美数学的证明依靠严密的逻辑推理&#xff0c;一经证明就永远正确&#xff0c;所以&#xff0c;数学证明是绝对的。相对而言&#xff0c;科学的证明则依赖于观察、实验数据和理解力&#xff0c;科学理论的证明难以达到数学定理证明所具有…

多年前那些优秀的工程师,后来都去哪儿了?

这是头哥侃码的第241篇原创上周末&#xff0c;我读初中的儿子突然问我&#xff1a;“爸爸&#xff0c;你是不是从好买离职了&#xff1f;”我听完&#xff0c;忙惊讶地问他是怎么知道的。他朝我做了个鬼脸&#xff0c;然后指了指我的手机说&#xff1a;“你的文章写的如此生动&…

使用easyUI 格式化datagrid列

author YHC 以下示例格式化在easyui DataGrid 里的列数据,和使用自定义列formatter ,如果价格小于20就将文本变为红色. 查看 Demo 格式化一个DataGrid 列,我们需要设置formatter 属性它是一个函数,这个格式化函数包含三个参数: value: 当前列对应字段值.row: 当前的row(行)记录…

收藏 | 分享 3 种脑洞大开的Excel技巧

全世界只有3.14 % 的人关注了数据与算法之美身为职场人&#xff0c;Excel基本是每天都会打开的软件&#xff0c;如果把对它的使用熟练程度分个等级&#xff0c;大概可以分为几下几种&#xff1a;Level 1&#xff1a;对Excel的基本功能已经有所了解&#xff0c;但还不熟练&#…

yaml for java_细数Java项目中用过的配置文件(YAML篇)

灵魂拷问&#xff1a;YAML&#xff0c;在项目中用过没&#xff1f;它与 properties 文件啥区别&#xff1f;目前 SpringBoot、SpringCloud、Docker 等各大项目、各大组件&#xff0c;在使用过程中几乎都能看到 YAML 文件的身影。2017 年的时候&#xff0c;我才真正把 YAML 文件…

超全面!8 种互联网常用生命周期完整指南~

什么是生命周期&#xff1f; 百度给出的定义是&#xff1a;生命周期就是指一个对象的生老病死。 生命周期的概念应用很广泛&#xff0c;特别是在政治、经济、环境、技术、社会等诸多领域经常出现&#xff0c;其基本涵义可以通俗地理解为“从摇篮到坟墓”的整个过程。对于某个…