当前位置: 首页 > news >正文

Route组件GetVirtualPath方法性能优化结果

由于使用Lambda表达式生成URL的方式性能较差,因此我使用Fluent Interface来代替原有的Lambda表达式构建方式。Fluent Interface主要对生成URL的前两个阶段(创建对象及分析对象)进行了优化,分别带来了超过2/3和1/2的性能优化,但因为最后一步,也就是使用Route对象的GetVirtualPath方法构造URL的性能没有提高,因此总体性能只提高了30%。于是我打算重新实现GetVirtualPath方法,希望得到更好的性能。

我的实现放在MvcPatch中MvcPatch.Routing项目里的FastRoute类。FastRoute的使用与ASP.NET Routing自带的Route比较相似,可以通过URL Pattern,Defaults及Constraints构造一个对象,而实际使用过程中可以通过MvcPatch.Extensions项目中定义的MapFast扩展方法进行注册。FastRoute将GetRouteData方法直接委托给内部的Route对象,但是重新实现了一个性能较高的GetVirtualPath方法。

说出来有些好笑,事实上我并没有完全理解GetVirtualPath的行为,我只是让GetVirtualPath方法通过了一些Test Case而已,这些Case的来源是我的“期望”以及微软官方,及我实际项目中所总结出来的使用方式。从目前看来,应该没有太大问题,最有可能出现问题的原因是我对Route对象本身的“设想”有所偏差,但它的确满足我目前的实际需求。

此外,在原版的Route对象中,Constraints集合支持两种约束方式,即“正则表达式”及“IRouteConstraint对象”。前者为开发人员提供的一个字符串,效果自不必说,而后者则是一个实现IRouteConstraint接口的对象。这个接口有一个Match方法,会将用于构造数据的RouteValueDictionary集合传入该方法,并返回一个布尔值表明是否满足该约束。它对性能的伤害之处需要完整复制一份的RouteValueDictionary(因为我们无法保证Match方法不会修改这个集合)。由于实际情况下我还从来没有真正使用过这个功能,因此将其抛弃。不过,如果真实现这个功能的话性能应该也不会差太多,因为假如开发人员不提供此类约束方式,我们不去复制该集合即可。

FastRoute的GetVirtualPath方法性能提升主要在三个方面:

  1. 验证及字符串拼接同时进行:在Route类中,每次Match方法都会先验证一遍传入的数据是否满足规则,如果不满足则直接返回null,然后再根据默认值和用户提供的值进行合并得到最终使用的集合,再进行拼接。这种方式较为“美观”但由于需要多次遍历,并构造并填充一些额外的RouteValueDictionary,因此虽然时间复杂度没有提高,但是影响性能的常数较大。由于项目中基本上都是通过名称直接找到RouteBase对象,因此不会失败,一边验证一边拼接的做法性能较高。
  2. 使用快速的索引方式:Route类中的索引使用了字典,而FastRoute使用了较为丑陋的方式,将URL Pattern拆分为多个Token,并使用多个数组保存Token的信息,例如当前Token是个常量还是个占位符。字典本身性能已经很高了,但是使用数组保存数据后,可以直接通过下标来获取Token的信息,一边读取,一边填充目标数组(见下一条)。
  3. 使用高效的字符串拼接方式:Route类使用了StringBuilder进行字符串拼接,而FastRoute使用了性能更高的String.Concat方法。由于URL Pattern的Token数量以及需要多少Query String都是在拼接前可以分析出来的,因此FastRoute在生成字符串之前便已经确定了整个字符串数组的长度。然后便是从后向前逆序填充数组内容,这是因为URL靠后的部分可能需要省略,这样便在数组的那个位置填入空字符串即可。

总之,FastRoute的性能优势在于精打细算每步操作,并根据数据特征选择相对高效的做法。不过目前的实现非常丑陋,我会继续进行一些调整和改进。使用FastRoute后,四种生成方式的耗时如下:

您可以将它和上次的结果进行对比,如果将Raw的性能视为100,则使用Route和FastRoute时其他3种方法的性能得分便是:

 RouteFastRoute
Route19.4716711847.14237983
Lambda8.20831835711.82049872
Fluent12.3724953721.76159473

绘制成图表似乎更加一目了然:

pub?key=tKjqmrvUdjU-Q6ugVjCSTPg&oid=4&output=image

可见,FastRoute让纯粹通过Route构造URL的做法性能提高了1倍多,而使用Lambda表达式和Fluent的做法也有较为明显的性能提升。值得一提的是,Fluent + FastRoute的性能已经超过了原有Route的做法,这意味着如果之前Route构造方式的性能能够令人接受的话,则目前Fluent方式的性能也已够用了。

测试项目下载

相关文章

  • 各种URL生成方式的性能对比
  • 各种URL生成方式的性能对比(结论及分析)
  • 为URL生成设计流畅接口(Fluent Interface)
  • URL生成方式性能优化结果
  • Route组件GetVirtualPath方法性能优化结果

相关文章:

  • 吴恩达老师的神经网路和深度学习_02
  • 80后成人高考第二季
  • swoole 异步非堵塞 server/端 client/端 代码,已经测试完毕。贴代码
  • 肖不语
  • 01基础数据类型——list相关操作
  • Git学习教程(四):分枝和合并
  • mysql 存储过程、循环
  • 创建自己的功能区
  • 通读教程第二问
  • Supervisor配置
  • 闲话我的辫子2010-01-08
  • python-函数基础
  • Oracle中的等待事件是什么?如何理解并优化Oracle
  • XSS 和 CSRF 两种跨站攻击
  • 探索未知种族之osg类生物---渲染遍历之裁剪二
  • docker python 配置
  • Elasticsearch 参考指南(升级前重新索引)
  • Flex布局到底解决了什么问题
  • Go 语言编译器的 //go: 详解
  • leetcode378. Kth Smallest Element in a Sorted Matrix
  • MD5加密原理解析及OC版原理实现
  • Redash本地开发环境搭建
  • XML已死 ?
  • 从零开始的webpack生活-0x009:FilesLoader装载文件
  • 理解IaaS, PaaS, SaaS等云模型 (Cloud Models)
  • 聊聊springcloud的EurekaClientAutoConfiguration
  • 配置 PM2 实现代码自动发布
  • 前端临床手札——文件上传
  • 思维导图—你不知道的JavaScript中卷
  • 算法---两个栈实现一个队列
  • - 语言经验 - 《c++的高性能内存管理库tcmalloc和jemalloc》
  • 3月7日云栖精选夜读 | RSA 2019安全大会:企业资产管理成行业新风向标,云上安全占绝对优势 ...
  • #14vue3生成表单并跳转到外部地址的方式
  • #define与typedef区别
  • %check_box% in rails :coditions={:has_many , :through}
  • (17)Hive ——MR任务的map与reduce个数由什么决定?
  • (2022版)一套教程搞定k8s安装到实战 | RBAC
  • (BFS)hdoj2377-Bus Pass
  • (Redis使用系列) Springboot 使用redis实现接口Api限流 十
  • (初研) Sentence-embedding fine-tune notebook
  • (全注解开发)学习Spring-MVC的第三天
  • .net core 6 集成 elasticsearch 并 使用分词器
  • .NET Core 中插件式开发实现
  • .netcore如何运行环境安装到Linux服务器
  • .NET教程 - 字符串 编码 正则表达式(String Encoding Regular Express)
  • @Autowired自动装配
  • [android] 天气app布局练习
  • [CareerCup] 2.1 Remove Duplicates from Unsorted List 移除无序链表中的重复项
  • [CSAWQual 2019]Web_Unagi ---不会编程的崽
  • [Gradle] 在 Eclipse 下利用 gradle 构建系统
  • [Grafana]ES数据源Alert告警发送
  • [HackMyVM]靶场Crossbow
  • [HDU]2161Primes
  • [HJ73 计算日期到天数转换]
  • [iOS]-UIKit