URL生成方式性能优化结果
2016-07-29 00:00
429 查看
继上次发现URL生成的性能问题之后,我最近一直在关注一些细节的性能优化。这些优化方式不是宏观的,理论的,而是在实践上对相同问题的不同做法进行探索。我把探索的过程和结论都发布在博客上了,从结果上看性能提高是比较明显的。但是,把它们用于解决实际问题时,效果又会如何呢?我把MvcPatch进行了一些修改,然后再使用UrlGenBenchmark进行了一番比较。
对于性能方面的优化,我做了以下一些改进。首先,我使用Fluent Interface来代替原有的Lambda表达式构建方式,期望可以减小表达式树构建的开销。此时,原本使用Lambda表达式的做法:
现在就变成了:
此外,对于Attribute标记Binder的做法也作了一些处理,不过没有使用昨天谈到的优化方式,而是通过在Model Binder类型标记RunnableAttribute的做法来复用对象。例如:
同时,如果CustomBinderAttribute也被标记了Runnable,那么这个Attribute也可以被复用。如MvcPatch中的BinderAttribute就被标记为Runnable。更细节的做法可参考MvcPatch及UrlGenBenchmark项目的源代码。
经过测试,我们可以得到如下结果:
将其绘制成图表:
而每秒生成页面的数量则是:
从结果上看,Fluent的做法比Lambda的性能有大约30%的提升,但是和Route,尤其是Raw的做法有明显的差距。在上一篇文章最后我们分析过,使用Lambda构建URL会经历三个部分,它们所占消耗分别是:
构造表达式树:约占29%。
解析和运算表达式树:约占30%。
使用Route生成URL:约占41%。
而使用Fluent Interface时,第一步,即构造对象的阶段,其开销是Lambda表达式的1/3。同时,最后一个步骤的开销不变。因此我们可以估算出第二个步骤的性能提升程度x:
等号左边两个数字分别是目前Fluent和Lambda两种做法消耗的时间。通过这个方程我们得出x大约是0.51,也就是说在第二步中我们也获得了大约50%的性能提高。客观来说,这个提升还是比较明显的。不过,绝对来看,这个结果并不让我十分满意。不过可能目前还能进行优化的应该是第3个步骤,那么我是否要朝这个方向努力呢?
您可以在这里下载到UrlGenBenchmark V2的代码,然后通过访问以下几个URL来查看各种生成方式的性能:
/benchmark?iteration=1000&view=ByRaw:使用拼接字符串的方式生成URL
/benchmark?iteration=1000&view=ByRoute:使用Route生成URL
/benchmark?iteration=1000:使用Lambda表达式生成URL
/benchmark?iteration=1000&view=ByFluent:使用Fluent Interface生成URL
各种URL生成方式的性能对比(结论及分析)
为URL生成设计流畅接口(Fluent Interface)
URL生成方式性能优化结果
Route组件GetVirtualPath方法性能优化结果
对于性能方面的优化,我做了以下一些改进。首先,我使用Fluent Interface来代替原有的Lambda表达式构建方式,期望可以减小表达式树构建的开销。此时,原本使用Lambda表达式的做法:
public static string ToPost(this UrlHelper helper, Blog blog, Post post) { return helper.Action<BlogController>(c => c.Post(blog, post)); }
现在就变成了:
public static string ToPostByFluent(this UrlHelper helper, Blog blog, Post post) { return helper.To<BlogController>().Action(c => c.Post, blog, post); }
此外,对于Attribute标记Binder的做法也作了一些处理,不过没有使用昨天谈到的优化方式,而是通过在Model Binder类型标记RunnableAttribute的做法来复用对象。例如:
同时,如果CustomBinderAttribute也被标记了Runnable,那么这个Attribute也可以被复用。如MvcPatch中的BinderAttribute就被标记为Runnable。更细节的做法可参考MvcPatch及UrlGenBenchmark项目的源代码。
[Reusable] public class PostBinder : IModelBinder, IRouteBinder { ... }
经过测试,我们可以得到如下结果:
将其绘制成图表:
而每秒生成页面的数量则是:
从结果上看,Fluent的做法比Lambda的性能有大约30%的提升,但是和Route,尤其是Raw的做法有明显的差距。在上一篇文章最后我们分析过,使用Lambda构建URL会经历三个部分,它们所占消耗分别是:
构造表达式树:约占29%。
解析和运算表达式树:约占30%。
使用Route生成URL:约占41%。
而使用Fluent Interface时,第一步,即构造对象的阶段,其开销是Lambda表达式的1/3。同时,最后一个步骤的开销不变。因此我们可以估算出第二个步骤的性能提升程度x:
14.37 / 21.67 = 0.29 / 3 + 0.3 * x + 0.41
等号左边两个数字分别是目前Fluent和Lambda两种做法消耗的时间。通过这个方程我们得出x大约是0.51,也就是说在第二步中我们也获得了大约50%的性能提高。客观来说,这个提升还是比较明显的。不过,绝对来看,这个结果并不让我十分满意。不过可能目前还能进行优化的应该是第3个步骤,那么我是否要朝这个方向努力呢?
您可以在这里下载到UrlGenBenchmark V2的代码,然后通过访问以下几个URL来查看各种生成方式的性能:
/benchmark?iteration=1000&view=ByRaw:使用拼接字符串的方式生成URL
/benchmark?iteration=1000&view=ByRoute:使用Route生成URL
/benchmark?iteration=1000:使用Lambda表达式生成URL
/benchmark?iteration=1000&view=ByFluent:使用Fluent Interface生成URL
相关文章
各种URL生成方式的性能对比各种URL生成方式的性能对比(结论及分析)
为URL生成设计流畅接口(Fluent Interface)
URL生成方式性能优化结果
Route组件GetVirtualPath方法性能优化结果
相关文章推荐
- 适合C# Actor的消息执行方式(6):协变与逆变
- Keynote,对不起,我爱的是PowerPoint 2007
- 优化通过表达式树构造URL的性能
- 在视图中使用递归生成树状结构
- 从今日起正式加入水果党
- 我们不是牛人,所以还是老老实实跟着兴趣走吧
- Mono开发者在21天内实现Linux Silverlight
- 适合ASP.NET MVC的视图片断缓存方式(中):更实用的API
- Gadget,又见Gadget - 浅尝Windows Live Contacts Gadget
- WPF/E CTP Quick Start - 第五部分:公有图形属性(翻译)
- 数十行F#打造简易Comet聊天服务
- 深入Atlas系列:Web Sevices Access in Atlas(7) - RTM中的客户端支持
- 趣味编程:C#中Specification模式的实现
- 我们是不是建立一个培训的用户群比较好呢?
- UpdatePanel与UrlRewrite
- 在QCon中了解到的一些有关Groovy和F#的内容
- 浅谈代码着色(上):客户端着色
- ASP.NET Routing对请求的处理方式
- [公告]WPF/E学习与研究团队成立 - WPF/E已经来了!
- 我的TDD实践:可测试性驱动开发(下)