Hello World
Spiga

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

2009-12-08 01:32 by 老赵, 6002 visits

由于使用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种方法的性能得分便是:

  Route FastRoute
Route 19.47167118 47.14237983
Lambda 8.208318357 11.82049872
Fluent 12.37249537 21.76159473

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

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

测试项目下载

相关文章

Creative Commons License

本文基于署名 2.5 中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名赵劼(包含链接),具体操作方式可参考此处。如您有任何疑问或者授权方面的协商,请给我留言

Add your comment

20 条回复

  1. 老赵
    admin
    链接

    老赵 2009-12-08 01:39:00

    对于看不到图片的朋友来说……
    1、一定要想办法让自己看到
    2、参考第1条
    3、可临时参考这里的截图

  2. 翻强出来的[未注册用户]
    *.*.*.*
    链接

    翻强出来的[未注册用户] 2009-12-08 01:57:00

    那就翻墙看吧
    随便测试下回复的速度!

  3. 晚上过来瞧一瞧[未注册用户]
    *.*.*.*
    链接

    晚上过来瞧一瞧[未注册用户] 2009-12-08 01:57:00

    看来熬夜的不只俺一个哈。。支持下 。。。

  4. xiaotie
    *.*.*.*
    链接

    xiaotie 2009-12-08 02:34:00

    还有几个夜猫子

  5. 老赵
    admin
    链接

    老赵 2009-12-08 09:11:00

    怎么都是半夜的回复啊,兄弟们太强了

  6. doylecnn
    *.*.*.*
    链接

    doylecnn 2009-12-08 10:15:00

    其实以后引用google docs上的文档及其图片的时候,多给个使用https的连接不就可以了么

  7. 老赵
    admin
    链接

    老赵 2009-12-08 10:18:00

    @doylecnn
    原来https是可以的阿,以前好像是不行的……

  8. 潜水冠军[未注册用户]
    *.*.*.*
    链接

    潜水冠军[未注册用户] 2009-12-08 10:22:00

    doylecnn:其实以后引用google docs上的文档及其图片的时候,多给个使用https的连接不就可以了么


    对,这个以前可以,后来又不可以了。现在又行了?

  9. 李永京
    *.*.*.*
    链接

    李永京 2009-12-08 10:26:00

    看到图了~~~

  10. MyCoolDog
    *.*.*.*
    链接

    MyCoolDog 2009-12-08 12:03:00

    您好~ 可以介绍一下您的msdn webcast上mvc课程哪些已经过时可以不看吗?

  11. 韦恩卑鄙 alias:v-zhewg
    *.*.*.*
    链接

    韦恩卑鄙 alias:v-zhewg 2009-12-08 13:18:00

    看到了 恩

  12. Ivony...
    *.*.*.*
    链接

    Ivony... 2009-12-08 13:52:00

    刚看到,又被墙了。。。。

  13. 老赵
    admin
    链接

    老赵 2009-12-08 14:09:00

    看到了是因为我用https了……

  14. winter-cn
    *.*.*.*
    链接

    winter-cn 2009-12-08 17:21:00

    Jeffrey Zhao:
    对于看不到图片的朋友来说……
    1、一定要想办法让自己看到
    2、参考第1条
    3、可临时参考这里的截图


    老赵不厚道 哈哈

  15. Will Meng
    *.*.*.*
    链接

    Will Meng 2009-12-09 13:44:00

    晕死,突然发现用G自己的浏览器可以正常浏览图片和表格

  16. Will Meng
    *.*.*.*
    链接

    Will Meng 2009-12-09 13:50:00

    感谢您的回复:) 提交耗时317600毫秒
    第一次看见这么长的。
    又不行了,老赵再做实验吗?

  17. 老赵
    admin
    链接

    老赵 2009-12-09 14:01:00

    Will Meng:晕死,突然发现用G自己的浏览器可以正常浏览图片和表格


    能看到图片是因为我改成https了。

  18. 老赵
    admin
    链接

    老赵 2009-12-09 14:01:00

    Will Meng:
    感谢您的回复:) 提交耗时317600毫秒
    第一次看见这么长的。
    又不行了,老赵再做实验吗?


    博客园又不是我在管理……

  19. Will Meng
    *.*.*.*
    链接

    Will Meng 2009-12-09 14:18:00

    @Jeffrey Zhao
    呵呵,看来我的话产生歧义了。
    我说老赵再做实验不是指提交评论的实验,我说的是你可能是在一会把https改成http一会又改回去。
    因为我之前看到表格了,再刷新又看不见了。
    要是以后能直接看到,我就不用代理了再。

  20. Ivony...
    *.*.*.*
    链接

    Ivony... 2009-12-09 17:30:00

    其实我觉得Route可以被编译。。。。。

    每一个不同的Pattern编译成不同的Route类型,这样是性能最好的。。。。

发表回复

登录 / 登录并记住我 ,登陆后便可删除或修改已发表的评论 (请注意保留评论内容)

昵称:(必填)

邮箱:(必填,仅用于Gavatar

主页:(可选)

评论内容(大于5个字符):

  1. Your Name yyyy-MM-dd HH:mm:ss

使用Live Messenger联系我