各种URL生成方式的性能对比

在上一篇文章中我们列举了各种URL生成的方式,其中大致可以分为三类:

  1. 直接拼接字符串(方法一及方法二)
  2. 使用Route规则生成URL(方法三)
  3. 使用Lambda表达式生成URL(方法四及方法五)

我们可以轻易得知,这3种作法可维护性依次增加,而性能依次减少。不过,我们还是有一个疑问,这个性能究竟相差多少?它是否的确真的可以被忽略?为此,我们还是来进行一次性能对比吧。

测试对象

为了获得贴近实际的测试结果,我打算以我的博客首页作为测试对象。您可以发现,这个页面上的链接非常多,我把它分为三个部分:

  1. 文章(Post)列表:主体部分的40篇文章,其中每篇文章包含1个详细页链接以及5个Tag。
  2. 边栏文章列表:假设边栏列举了120篇文章的链接。
  3. 归档(Archive)列表:也就是每个月的文章链接,3年共36个链接。

作为一个演示,我也精心准备了四种URL模式,它们分别是:

// 博客首页
routes.MapRoute("Blog.Index","{blog}",new { controller = "Blog", action = "Index" });// 标签页
routes.MapRoute("Blog.Tag","{blog}/tag/{tag}",new { controller = "Blog", action = "Tag" });// 按月归档页
routes.MapRoute("Blog.Archive","{blog}/archive/{year}/{month}.html",new { controller = "Blog", action = "Archive" });// 文章详细页
routes.MapRoute("Blog.Post","{blog}/archive/{*post}",new { controller = "Blog", action = "Post" });

以上代码在Web项目中的GlobalApplication.cs文件中。您可以发现,我完全按照博客园在定制URL的模式。我想说明的是,其实URL Routing完全非常灵活,您可以根据需求使用各种形式的URL,关键只是“规则配置”而已。不过虽然配置了4种Route规则,但是我只实现了BlogController下的一个Action:博客首页(Index),如下:

[RouteName("Blog.Index")]
public ActionResult Index([ModelBinder(typeof(BlogBinder))]Blog blog, string view)
{var model = new IndexModel { Blog = blog, Posts = GetPosts() };return View("Index" + view, model);
}private static List<Post> GetPosts()
{...
}[RouteName("Blog.Post")]
public ActionResult Post([ModelBinder(typeof(BlogBinder))]Blog blog,[ModelBinder(typeof(PostBinder))]Post post)
{throw new NotImplementedException();
}[RouteName("Blog.Tag")]
public ActionResult Tag([ModelBinder(typeof(BlogBinder))]Blog blog,[ModelBinder(typeof(StringBinder))]string tag)
{throw new NotImplementedException();
}[RouteName("Blog.Archive")]
public ActionResult Archive([ModelBinder(typeof(BlogBinder))]Blog blog,int year,int month)
{throw new NotImplementedException();
}

BlogController.cs文件处于Web.Controllers项目中。我为每个复杂参数都安排了ModelBinder,具体实现都很简单,您可以下载文末的代码进行浏览。在GetPosts里我将准备40个Post对象,每个Post对象分配5个Tag,这些都将显示在页面上。Index方法的参数view通过Query String进行传递,例如,您可以通过一下三个链接来访问不同的URL生成方式:

  • /jeffz?view=ByRaw:使用拼接字符串的方式生成URL
  • /jeffz?view=ByRoute:使用Route规则生成URL
  • /jeffz:使用Lambda表达式这个“推荐方式”生成URL

三种方式

在Web.UI项目中的Views目录下有BlogController所使用的三个视图模板,他们使用不同的方式来生成完全一样的内容。例如Index.aspx文件中的定义是这样的:

<!-- 主体文章列表,40篇,各5个Tag -->
<h2>Posts</h2>
<ul><% foreach (var post in Model.Posts) { %>
        <li>Title: <a href="<%= Url.ToPost(Model.Blog, post) %>"><%= Html.Encode(post.Title) %></a>Tag: <% foreach (var tag in post.Tags) { %>
                <a href="<%= Url.ToTag(Model.Blog, tag) %>"><%= Html.Encode(tag) %></a> | <% } %>
        </li><% } %>
</ul><!-- 边栏文章列表,共计120篇 -->
<h2>More post links</h2>
<ul><% for (int i = 0; i < 3; i++) { %>
        <% foreach (var post in Model.Posts) { %>
            <li style="display: inline;"><a href="<%= Url.ToPost(Model.Blog, post) %>"><%= Html.Encode(post.Title) %></a> |</li><% } %>
    <% } %>
</ul><!-- 归档列表,3年共计36个链接 -->
<h2>Archives</h2>
<ul><% for (int year = 2007; year <= 2009; year++) { %>
        <% for (int month = 1; month <= 12; month++) { %>
            <li><a href="<%= Url.ToArchive(Model.Blog, year, month) %>"><%= year %><%= month %></a></li><% } %>
    <% } %>
</ul>

对于IndexByRaw.aspxIndexByRoute.aspx来说,它们只是把ToPost,ToTag等方法改为对应的ToPostByRaw或ToTagByRoute而已。因此,其实生成URL的关键还在于这些辅助方法。例如ToPost,ToTag和ToArchive三个扩展方法是这样实现的:

public static string ToPost(this UrlHelper helper, Blog blog, Post post)
{return helper.Action<BlogController>(c => c.Post(blog, post));
}public static string ToTag(this UrlHelper helper, Blog blog, string tag)
{return helper.Action<BlogController>(c => c.Tag(blog, tag));
}public static string ToArchive(this UrlHelper helper, Blog blog, int year, int month)
{return helper.Action<BlogController>(c => c.Archive(blog, year, month));
}

可见,使用Lambda表达式构造URL的代码非常清晰,简单,直观——因为Action辅助方法会自动从Lambda表达式中提取Controller和Action名,并调用每个参数的RouteBinder实现复杂类型参数的双向转化,它不需要我们关心更多的东西。

而如果直接拼接字符串,那么它可能就是这样的:

public static string ToTagByRaw(this UrlHelper helper, Blog blog, string tag)
{return blog.Alias + "/tag/" + HttpUtility.UrlEncode(tag);
}

而基于Route构造URL就会显得略麻烦一些:

public static string ToTagByRoute(this UrlHelper helper, Blog blog, string tag)
{var path = helper.RouteCollection.GetVirtualPathEx(helper.RequestContext,"Blog.Tag",new RouteValueDictionary{{ "controller", "Blog" },{ "action", "Tag" },{ "blog", blog.Alias },{ "tag", HttpUtility.UrlEncode(tag) }});return path.VirtualPath;
}

至于后两种方式的其它几个辅助方法,您可以下载文末的代码进行浏览,它们都在Web.Controllers项目中的UrlGenExtensions.cs文件中。

运行测试

我们使用BlogController中另一个Action方法:Benchmark进行性能测试。Benchmark方法接受两个参数,一个是循环次数,而另一个则是测试目标:

public ActionResult Benchmark(int iteration, string view)
{var model = new IndexModel{Blog = new Blog { Alias = "jeffz" },Posts = GetPosts()};var result = new BenchmarkModel{Iteration = iteration,View = "Index" + view};var viewInstance = new WebFormView("~/Views/Blog/Index" + view + ".aspx");var viewContext = new ViewContext(this.ControllerContext,viewInstance,new ViewDataDictionary(model),new TempDataDictionary());// warm upviewInstance.Render(viewContext, new StringWriter());GC.Collect();var watch = new Stopwatch();watch.Start();for (int i = 1; i <= iteration; i++){viewInstance.Render(viewContext, new StringWriter());if (i % 100 == 0){result.Add(i, watch.Elapsed);}}watch.Stop();return View(result);
}

于是,您可以使用下面的链接观察使用三种方法生成1000次页面所消耗的时间:

  • /benchmark?iteration=1000&view=ByRaw:使用拼接字符串的方式生成URL
  • /benchmark?iteration=1000&view=ByRoute:使用Route生成URL
  • /benchmark?iteration=1000:使用Lambda表达式生成URL

Benchmark方法会每隔100次记录一下结果,因此上面的链接加载完后会出现10条信息——这便是我们得到的结果。

结果

至于最终的结果以及分析,我打算暂时卖个关子,不多久我就会独立开篇进行说明的。您可以在这里下载到整个解决方案,代码不多,但也花费了我2个小时进行准备,您可以亲自试验一下。您直接使用上面的Benchmark链接进行观察即可,生成1000次页面已经足以展示一些问题了——不过在此之前,您不妨进行一个预测,猜猜看它们之间究竟有多大的性能差距。

相关文章

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

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

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

相关文章

element-ui中el-table的表头、内容样式

方式1&#xff1a; 直接在标签上添加上属性值&#xff1a; <el-table:header-cell-style"{background:#F3F4F7,color:#555}" ></el-table>方式2&#xff1a; 在method里面写上方法&#xff1a; rowClass({ row, rowIndex}) {console.log(rowIndex) //表…

python下设置urllib连接超时

From: http://blog.csdn.net/vah101/article/details/6175406 首先导入socket库 import socket 在开始连接前的代码中&#xff0c;再加入 socket.setdefaulttimeout(6) #6秒内没有打开web页面&#xff0c;就算超时 然后就可以开始连接了&#xff0c;比如 try: …

请移步到我的新浪博客

请移步到我的新浪博客http://blog.sina.com.cn/highlandcat转载于:https://blog.51cto.com/highlandcata/221449

疯狂喷气机

2/3D游戏&#xff1a;2D 辅助插件&#xff1a;原生 游戏制作难度系数&#xff1a;初级 游戏教程网址&#xff1a;http://www.raywenderlich.com/69392/make-game-like-jetpack-joyride-unity-2d-part-1 1、控制摄像机跟随人物移动 public GameObject targetObject; //目标对象p…

elementui表格-改变某一列的样式

cellStyle({ row, column, rowIndex, columnIndex }) {if (columnIndex 0) {// 指定列号return ‘padding:0‘} else {return ‘‘} },

正则表达式基础(一)

From: http://www.usidcbbs.com/read-htm-tid-1457.html Perl 中的正则表达式 正则表达式是 Perl 语言的一大特色&#xff0c;也是 Perl 程序中的一点难点&#xff0c;不过如果大家能够很好的掌握他&#xff0c;就可以轻易地用正则表达式来完成字符串处理的任务&#xff0…

CodeSmith--SchemaExplorer类结构详细介绍

CodeSmith----SchemaExplorer类结构详细介绍 CodeSmith与数据库的联系&#xff0c;在CodeSmith中自带一个程序集SchemaExplorer.dll&#xff0c;这个程序集中的类主要用于获取数据库中各种对象的结构。 <% Property Name"SourceTable" Type"SchemaExplorer.T…

vue element项目常见实现表格内部可编辑功能

目录 前言 正文 1.简单表格行内内部可编辑 2. 数据从后端取得表格行内可编辑 3.批量表格整体的可编辑 结语 前言 后台系统都是各种表格表单编辑&#xff0c;整理了下常见的几种实现表格编辑的方式&#xff0c;希望有用。使用框架&#xff1a;vueelement 表格行内内部可编辑 数…

tar

tar命令是Unix的一个shell命令&#xff0c;该命令可在为多个制定文件创建一个档案文件&#xff0c;也可以从一个档案文件中解压缩出文件。tar档案文件的扩展名为“.tar”。tar包中的文件并不是压缩文件&#xff0c;而是所有文件集合成的一个文件。 tar这个名字源自在磁带上备份…

Yii2.0 技巧总结

View部分 1. 使用ActiveField中的hint生成提示文字 <? $form->field($model, freightAddedFee)->textInput()->hint(大于0的整数) ?> 2. 文本框添加placeholder属性&#xff0c;其实这个本来就是html5带的属性。 <? $form->field($model, mobile, $inp…

React开发(157):一级直接用getFieldDecorator

<Row gutter{12}><Col span{12}><Form.Item label"省/市/区">{getFieldDecorator(proviceValue, {initialValue: proviceValue,rules: [{ required: true, message: 公司人数不能为空 }],})(<CascaderfieldNames{fieldNames}options{options}on…

【JavaScript】appendChild一个的注意点之会删除原dom树节点

最近在研究学习vue原理&#xff0c;其中使用createDocumentFragment()方法&#xff0c;是用来创建一个虚拟的节点对象&#xff0c;那问题来了&#xff0c;创建了虚拟dom树&#xff0c;且最后只渲染了虚拟dom树里面的节点&#xff0c;那原dom树的节点去哪里了&#xff0c;查阅了…

正则表达式图书

From: http://www.usidcbbs.com/read-htm-tid-1457-page-2.html 网文 vs 书藉 只要是知道“正则”这个词的&#xff0c;上网搜集个把资料&#xff0c;应该就不是问题吧。我获得正则消息的网絡渠道有这样几个&#xff0c;以质量从高到低排序&#xff1a;dilicious标签&#xff0…

Spring.NET学习笔记12——面向切面编程(基础篇) Level 300

AOP即面向切面编程(Aspect Oriented Programming的缩写)&#xff0c;是OOP(面向对象编程)的一种延续形式。是通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术&#xff0c;它从一个不同于OOP的角度来看待程序的结构&#xff1a;OOP将…

React开发(158):ant design级联回显 直接传入数组

ReactDOM.render(<CascaderdefaultValue{[zhejiang, hangzhou, xihu]}options{options}onChange{onChange}/>,mountNode, );

vue-cli3使用svg图标的详细步骤

1.安装依赖 npm install svg-sprite-loader -D2.在vue.config.js里添加配置 module.exports{chainWebpack: config > {const svgRule config.module.rule("svg"); svgRule.uses.clear();svgRule.use("svg-sprite-loader").loader("svg-sprite…

网络工程师的忠告

诸位&#xff0c;咱当网络工程师也是几年了&#xff0c;不算有出息&#xff0c;环顾四周&#xff0c;也没有看见几个有出息的&#xff01;回顾工程师生涯&#xff0c;感慨万千&#xff0c;愿意讲几句掏心窝子的话&#xff0c;也算给咱们师弟师妹们提个醒&#xff0c;希望他们比…