Hello World
Spiga

优化通过表达式树构造URL的性能

2009-09-01 19:29 by 老赵, 5455 visits

我们继续改进通过表达式树构造URL的方式。在上一篇文章中,辅助方法可以正确地识别了ActionNameAttribute,而这次改进的则是性能方面的问题。首先还是来看一下用于从表达式树获取RouteValueDictionary的方法:

public static RouteValueDictionary GetRouteValues<TController>(
    Expression<Action<TController>> action)
    where TController : Controller
{
    ...

    var rvd = new RouteValueDictionary();
    rvd.Add("controller", controllerName);
    rvd.Add("action", GetActionName(call.Method));

    AddParameterValues(rvd, call);
    return rvd;
}

private static void AddParameterValues(
    RouteValueDictionary rvd, MethodCallExpression call)
{
    ParameterInfo[] parameters = call.Method.GetParameters();

    for (int i = 0; i < parameters.Length; i++)
    {
        Expression arg = call.Arguments[i];

        object value = null;
        ConstantExpression ce = arg as ConstantExpression;
        if (ce != null)
        {
            // If argument is a constant expression, just get the value
            value = ce.Value;
        }
        else
        {
            // Otherwise, convert the argument subexpression to type object,
            // make a lambda out of it, compile it, and invoke it to get the value
            Expression<Func<object>> lambdaExpression = 
                Expression.Lambda<Func<object>>(
                    Expression.Convert(arg, typeof(object)));
            Func<object> func = lambdaExpression.Compile();
            value = func();
        }

        rvd.Add(parameters[i].Name, value);
    }
}

这次我们关注的是第二个方法AddParameterValues。这个方法的目的是从表示action调用的表达式树(它是一个MethodCallExpression)中提取所有的参数——也是一个一个表达式树,并将它们表示的“值”填充到RouteValueDictionary中。这段代码使用了传统计算一个表达式树的方式:“使用LambdaExpression对象封装,再编译,最后执行”来获得一个Expression对象的值。但是,Compile方法的性能是比较低下的,如果密集地执行会对性能产生一定影响。

那么,您认为在ASP.NET MVC的场景中,Compile方法的执行频率如何呢?请想象一下这样的一个场景:

<h2>Article List</h2>
 
<% foreach (var article in Model.Articles) { %>
<div>
    <%= Html.ActionLink<ArticleController>(
            c => c.Detail(article.ArticleID, 1), article.Title) %>
    
    <% for (var page = 2; page <= article.MaxPage; page++) { %>
    <small>
        <%= Html.ActionLink<ArticleController>(
            c => c.Detail(article.ArticleID, page), page.ToString()) %>
    </small>
    <% } %>        
</div>
<% } %>

上述代码的作用,是在文章列表页上生成一系列指向文章详细页的链接。那么在上面的代码中,将会出现多少次表达式树的计算呢?

Html.ActionLink<ArticleController>(
    c => c.Detail(article.ArticleID, 1), article.Title)
 
Html.ActionLink<ArticleController>(
    c => c.Detail(article.ArticleID, page), article.Title)

可以看出,每篇文章将进行(2 * MaxPage – 1)次计算,对于一个拥有数十篇文章的列表页,计算次数很可能逾百次。此外,再加上页面上的各种其它元素,如分类列表,Tag Cloud等等,每生成一张略为复杂的页面便会造成数百次的表达式树计算。从Simone Chiaretta的性能测试上来看,使用表达式树生成链接所花时间,大约为直接使用字符串的30倍。而根据我的本地测试结果,在一台P4 2.0 GHz的服务器上,单线程连续计算一万个简单的四则运算表达式便要花费超过1秒钟时间。这并非是一个可以忽略的性能开销,引入一种性能更好的表达式树计算方法势在必行。

在《快速计算表达式树》一文中,我已经对这一话题进行了非常深入的探讨(甚至还可以算上表达式树的缓存这一系列文章),并最终给出了一个可以直接复用的解决方案:FastLambda。因此,我们在这里只需要使用如下的方式来改进表达式树的“计算”方式即可:

private static void AddParameterValues(
    RouteValueDictionary rvd, MethodCallExpression call)
{
    ParameterInfo[] parameters = call.Method.GetParameters();

    for (int i = 0; i < parameters.Length; i++)
    {
        rvd.Add(parameters[i].Name, Eval(call.Arguments[i]));
    }
}

private static FastEvaluator s_parameterEvaluator = new FastEvaluator();

private static object Eval(Expression exp)
{
    ConstantExpression ce = exp as ConstantExpression;
    if (ce != null) return ce.Value;

    return s_parameterEvaluator.Eval(exp);
}

FastEvaluator是FastLambda项目中提供的一个类,它会对输入的表达式树进行分析,并根据其结构缓存编译后的结果,于是下次输入结构相同的表达式时,便可以快速的计算出结果,省去了编译的开销。例如在上面的例子中,无论article指向的是什么对象,无论page的值是多少,article.ArticleID或page本身的结构永远是不变的。因此,对于刚才的例子,无论访问了多少次页面,作了多少次循环,都只会进行两次编译。此外,由于FastEvaluator已经实现为一个线程安全的组件,因此这里我们只须直接使用即可,无需进行太多考虑。

那么,这么做会带来多少性能提升呢?请看如下的示意图:

perf test

这幅图表达的是在计算拥有2n + 1个节点的表达式树时,普通的做法(红线)与FastEvaluator(紫线)的性能差距。根据我的个人经验,项目中所计算的表达式树的节点数量一般都在10个以内。如图所示,在这个数据范围内,FastEvaluator的计算耗时仅为传统方法的1/20。对于刚才的示例来说,节点数量为3或5,则表示n为1或3,在这种节点数量极少的情况下,性能的差距甚至可以达到50至100倍。

当然,一个应用程序的性能不是由这么简单的一个细节决定的,但是现在我们为一个较为频繁的操作进行了非常明显的性能优化。更重要的是,我们并没有因此损失任何易用性。因此,如果您在ASP.NET MVC中通过表达式树构造URL的话,我建议您使用现在的方案进行改进。

至于FastEvaluator组件的原理及实现等细节内容,还请参考我写的《快速计算表达式树》一文。

Creative Commons License

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

Add your comment

53 条回复

  1. 博客园一员
    *.*.*.*
    链接

    博客园一员 2009-09-01 19:32:00

    写的天书呢?看不懂

  2. 老赵
    admin
    链接

    老赵 2009-09-01 19:35:00

    @博客园一员
    仔细看看,会看懂的。
    如果还看不懂,等遇到这个问题之后就会懂了。

  3. 温景良(Jason)
    *.*.*.*
    链接

    温景良(Jason) 2009-09-01 19:36:00

    老赵的文章现在只能看看,理解需要深入

  4. 老赵
    admin
    链接

    老赵 2009-09-01 19:39:00

    @温景良(Jason)
    呵呵,回家了。

  5. Galactica
    *.*.*.*
    链接

    Galactica 2009-09-01 19:55:00

    楼主说话真绕。

  6. 麒麟.NET
    *.*.*.*
    链接

    麒麟.NET 2009-09-01 20:21:00

    博客园一员:写的天书呢?看不懂


    这个系列从头开始看,肯定能看懂。

    // 建议老赵等全写完后建个索引

  7. 老赵
    admin
    链接

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

    Galactica:楼主说话真绕。


    具体谈谈?

  8. RednaxelaFX
    *.*.*.*
    链接

    RednaxelaFX 2009-09-01 21:40:00

    看到这个我是突然想起DLR里有个用于解释执行Expression Tree用的解释器。本来是为提高基于DLR的语言的启动性能用的,也可以拉出来单独用。只能针对DLR或者.NET 4.0的ETv2来用。不过要是改造一下用在ETv1上应该也能行的,实现还更简单些。
    可以跟缓存编译结果的方式比对下什么范围内哪边的性能更好 ^ ^

  9. 老赵
    admin
    链接

    老赵 2009-09-01 21:43:00

    @RednaxelaFX
    我一直下不了狠心去读DLR的代码,有机会一定要看看,赫赫。

  10. 老赵
    admin
    链接

    老赵 2009-09-01 21:45:00

    @RednaxelaFX
    话说,其实现在的方式,其性能关键是在于“从缓存中查找”的操作,它和节点数量是线性相关的。
    那附图里的测试数据其实都只是几十个数的加减乘除,说实话都是在图表上看不出来的耗时……
    所以,如果要优化现在的做法,还得从缓存方式入手。现在做的蛮粗糙的,的确有优化余地,赫赫。

  11. xmanx[未注册用户]
    *.*.*.*
    链接

    xmanx[未注册用户] 2009-09-02 09:34:00

    public RouteValueDictionary GetRouteValues<TController>(
    Expression<Action<TController>> action)
    where TController : Controller
    {
    ...
    AddParameterValues(rvd, call);
    return rvd;
    }

    private void AddParameterValues(
    RouteValueDictionary rvd, MethodCallExpression call)
    {
    ParameterInfo[] parameters = call.Method.GetParameters();
    foreach(ParameterInfo pi in parameters)
    {
    using (ConstantExpression ce = arg as ConstantExpression)
    {
    object value = null;
    //下面这句不能用i
    Expression arg = call.Arguments[i];
    if (ce != null)
    {
    // If argument is a constant expression, just get the value
    value = ce.Value;
    }
    else
    {
    ...
    }
    rvd.Add(pi.Name, value);
    }
    }
    }

    1.静态是要FIFO的
    2.代码要考虑全面,免得教错别人

  12. 老赵
    admin
    链接

    老赵 2009-09-02 09:47:00

    @xmanx
    为什么不能用i?你贴的代码用foreach就不方便了(因为要同时访问两个等长的数组/集合),所以我用for。
    你为什么要用using,ConstantExpression又不是Disposable的。
    还有,我为什么看不懂你的意思?什么叫做静态是要FIFO的?
    考虑全面是需要的,不过……你觉得我哪里没有考虑全面?

  13. xmanx[未注册用户]
    *.*.*.*
    链接

    xmanx[未注册用户] 2009-09-02 09:50:00

    静态的只有一个内存地址,所以如果这个函数执行的时候,其他需要执行的无法读取该地址
    只能等待处理完以后读取,没有漏for,修改为foreach,减少再去搜索数组Arguments[i]

  14. 老赵
    admin
    链接

    老赵 2009-09-02 09:56:00

    @xmanx
    你的意思是“静态方法”没法被多个线程同时执行?这怎么可能。
    修改为我认为foreach没有必要,这里需要同时访问两个等长的数组/集合,用for最方便。
    用foreach之后还要再次通过累加器计算下标。这里用foreach性能又差程序又难写难懂。

  15. 韦恩卑鄙
    *.*.*.*
    链接

    韦恩卑鄙 2009-09-02 10:01:00

      public delegate TResualt IndexedSelector<TValue, TIndex, TResualt>(TValue value, TIndex index);
      
      static public IEnumerable<TResualt> Select<T, TResualt>(this T[] array, int start, int repeatTime, int incSeed, IndexedSelector<T, int, TResualt> selector)
            {
                if (start + (repeatTime - 1) * incSeed > array.Length || start + (repeatTime - 1) * incSeed < 0)
                {
                    throw new System.ArgumentOutOfRangeException("start + (repeatTime - 1) * incSeed", "array is too sort to do this");
    
                }
    
                for (var i = 0; i < repeatTime; i++)
                {
                    var tmp_index = incSeed * i + start;                
                    yield return selector(array[tmp_index], tmp_index); 
                }
    
            }
    

  16. xmanx[未注册用户]
    *.*.*.*
    链接

    xmanx[未注册用户] 2009-09-02 10:02:00

    没有什么认为必要不必要
    测试过才可以说"认为"两个字;“静态方法”说的是一个w3wp线程运行,需要等待,for和foreach你自己测试数据就明白了

    本来懒得说,毕竟你的文章漏洞太多,教坏别人就不好了,而且全部是片断代码,新入门的无法看懂,你是在推销你的书还是在写技术心得,怀疑

  17. 老赵
    admin
    链接

    老赵 2009-09-02 10:07:00

    @xmanx
    我无语了,foreach和for的性能你测试过吗?我测试过,给你看结果。
    http://www.cnblogs.com/JeffreyZhao/archive/2009/05/29/generic-performance-test.html
    foreach是语义好,性能不如for。我平时推荐foreach的场景也是因为编程方便。

    还有什么一个w3wp线程,静态方法需要等待?简直是笑话。
    如果你说是单个线程,本来就是同步的,和静态方法有什么关系?

    我推销自己的书?我哪里有书?我推销什么?
    我的文章可能有漏洞,但是你说的绝对是无中生有。

    // 不知哪位朋友看懂了xmanx的意思,帮忙解释一下。如果是我错了,我自然会修改和道歉。

  18. 韦恩卑鄙
    *.*.*.*
    链接

    韦恩卑鄙 2009-09-02 10:08:00

    晕了 从linq一出来就测过foreach 会比index慢 被人一句话 否决了

    老赵这个系列写了快大半年了 你看不懂能不能从去年的开始补习呢

  19. xmanx[未注册用户]
    *.*.*.*
    链接

    xmanx[未注册用户] 2009-09-02 10:12:00

    测试结果看错了,刚才
    for是最快的,代码慢在

    for (int i = 0; i < parameters.Length; i++)

    var plen=parameters.Length;
    for (int i = 0; i <plen ; i++)

    这两个效率的差距

  20. 韦恩卑鄙
    *.*.*.*
    链接

    韦恩卑鄙 2009-09-02 10:16:00

    老赵 你能不能把你的这n篇关于fast lambda 表达式树的文章 按照思维脉络 做个图呢

    比如 终极目标是提供高性能的强类型mvc开发体验 所以

    1 提高体验的方式 全强类型 用lbd表达式
    2 提高体验带来的代价
    3 代价根本原因
    4 如何减少代价 方法论
    5 如何减少代价 相关研究 表达式树
    6 如何减少代价 实现细节



    这样新看你文章的人就会比较了解自己在哪里了哦

  21. xmanx[未注册用户]
    *.*.*.*
    链接

    xmanx[未注册用户] 2009-09-02 10:17:00

    string[] xx=new string[999999];
    DateTime bd=System.DateTime.Now;
    for (int i = 0; i < 999999; i++)
    {
    string yy = xx[i];
    }
    DateTime md= System.DateTime.Now;
    foreach(string zz in xx)
    {
    string yy=zz;
    }
    DateTime ed = System.DateTime.Now;
    for (int i = 0; i < xx.Length; i++)
    {
    string yy = xx[i];
    }
    DateTime eed = System.DateTime.Now;
    string vvv=(md - bd).TotalMilliseconds.ToString() + "_" + (ed - md).TotalMilliseconds.ToString() + "_" + (eed - ed).TotalMilliseconds.ToString());

  22. 韦恩卑鄙
    *.*.*.*
    链接

    韦恩卑鄙 2009-09-02 10:21:00

    楼上知不知道 array 和list 的
    foreach
    在c# jit层默认被修改为 index访问了呢

    实际运行就是多了一个累加器 这个成本可以说大 也可以说小

  23. xmanx[未注册用户]
    *.*.*.*
    链接

    xmanx[未注册用户] 2009-09-02 10:23:00

    量级加到9999999
    15.624_49.8015_20.5065

    静态的就不说了,单个线程肯定会引起阻塞

  24. 老赵
    admin
    链接

    老赵 2009-09-02 10:23:00

    @韦恩卑鄙
    等我写完了整理一下吧。这个不容易啊……

  25. 老赵
    admin
    链接

    老赵 2009-09-02 10:24:00

    @xmanx
    一个需要每次访问Length属性,一个不需要,性能差距在这里。
    但是我觉得这个性能差距不是问题。
    我在这里说不同foreach也是因为“不方便”,“不清晰”而不是性能差。
    平时我会推荐使用foreach。

  26. 韦恩卑鄙
    *.*.*.*
    链接

    韦恩卑鄙 2009-09-02 10:24:00

    而且静态的FIFO是哪里听来的 -0-

  27. 老赵
    admin
    链接

    老赵 2009-09-02 10:26:00

    @xmanx
    什么叫做单个线程会引起阻塞?
    本来单个线程就是同步执行的,这个和调用静态方法还是实例方法有什么关系?
    如果是多个线程之间,同时访问static方法有什么不可以。

  28. xmanx[未注册用户]
    *.*.*.*
    链接

    xmanx[未注册用户] 2009-09-02 10:34:00

    string[]在赋值情况下
    for (int i = 0; i < 9999999; i++)
    {
    xx[i] = i.ToString() + Guid.NewGuid().ToString();
    }

    14.6475_23.436_278.3025

    既然写代码,给别人看就要考虑全面

    静态的你在IIS里面运行就明白了,用两台电脑访问服务器同一个静态函数

  29. 老赵
    admin
    链接

    老赵 2009-09-02 10:37:00

    @xmanx
    既然写代码,给别人看就要考虑全面
    静态的你在IIS里面运行就明白了,用两台电脑访问服务器同一个静态函数


    我还是想问,你说我哪里没有考虑全面?
    我在过去10多年里测试过无数次,拜托你测试一下在来发表意见行不行。
    两个线程同时访问static方法会引起阻塞?我真不知道你是哪里学到这个的。

  30. xmanx[未注册用户]
    *.*.*.*
    链接

    xmanx[未注册用户] 2009-09-02 10:43:00

    Jeffrey Zhao:

    @xmanx
    静态的你在IIS里面运行就明白了,用两台电脑访问服务器同一个静态函数


    我还是想说,我在过去10多年里测试过无数次,拜托你测试一下在来发表意见行不行。
    两个线程同时访问static方法会引起阻塞?我真不知道你是哪里学到这个的。



    我还是想说,我测试过无数次,拜托你测试一下在来发表意见行不行。
    一个线程访问static方法会引起阻塞,我真不知道你看清楚我写的字没有。IIS不开启web园,后台只有一个w3wp运行,如果静态函数没有执行完,那执行请求要等待执行完才可以

  31. 老赵
    admin
    链接

    老赵 2009-09-02 10:45:00

    @xmanx
    当然不开启web园,当然后台只有一个w3wp运行。谁说这样静态函数就会阻塞,会需要等待执行完的?
    好了,我就说到这里了,如果你没法相信,又坚持你那所谓的“测试”,我也没有办法了。
    旁观的兄弟们,根据你们自己的判断和测试看着办吧。

  32. xmanx[未注册用户]
    *.*.*.*
    链接

    xmanx[未注册用户] 2009-09-02 10:55:00

    你坚持你的,我坚持我的,我也没办法了
    其他人应该有测试结果,我相信他们的测试结果

    本来是提醒你,自己写代码考虑全面一些,是你的文章里面代码引起的

    自己写得不清楚,我也没有办法了,下次不留言了,只是怕你害了其他看你文章的新手

  33. 老赵
    admin
    链接

    老赵 2009-09-02 10:59:00

    @xmanx
    ……谢谢你的好意,我心领了。
    我强烈建议您以后发现我错误的时候,写一篇文章出来痛骂我一顿。
    最好发到首页,可以让更多的人看到。

  34. 韦恩卑鄙
    *.*.*.*
    链接

    韦恩卑鄙 2009-09-02 11:00:00

    可以在静态函数里面放个sleep试试 哈哈

  35. 老赵
    admin
    链接

    老赵 2009-09-02 11:04:00

    @韦恩卑鄙
    没错,一试便知:

    static void Test()
    {
        var start = DateTime.Now
        Thread.Sleep(1000);
        var end = DateTime.Now
    
        Response.Write(start + "<br/>" + end);
    }
    
    真不知道有什么值得争辩的。

  36. xmanx[未注册用户]
    *.*.*.*
    链接

    xmanx[未注册用户] 2009-09-02 11:11:00

    @韦恩卑鄙
    sleep是线程停止,并不是执行程序,w3wp暂时停止
    static void Test()
    {
    var start = DateTime.Now;
    var len=9999999;
    string[] xx=new string[len];
    for(int i=0;i<len;i++)
    {
    var obj=xx[i];
    obj=i.ToString()+Guid.NewGuid().ToString();
    }
    var end = DateTime.Now
    Response.Write(start + "<br/>" + end);
    }

  37. 韦恩卑鄙
    *.*.*.*
    链接

    韦恩卑鄙 2009-09-02 11:14:00

    static public class ClassStatic
    {
       static  public bool  ClassStaticQuery(System.Web.UI.Page page )
    	{
            System.Text.StringBuilder sb = new System.Text.StringBuilder("<xmp>");
            sb.AppendLine(DateTime.Now.ToString());
            System.Threading.Thread.Sleep(8000);
            sb.AppendLine(DateTime.Now.ToString());
            sb.AppendLine("</xmp>");
            page.Controls.Add(page.ParseControl(sb.ToString()));
            return true;
    	}
    }
    
    



    我在一个叶面 写
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    
    public partial class _Default : System.Web.UI.Page 
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            this.Response.Cache.SetExpires(DateTime.Now.AddDays(-1));
    
            ClassStatic.ClassStaticQuery(this);
        }
    }
    
    


    两个叶面一起刷新 结果分别为


    9/2/2009 11:11:48 AM
    9/2/2009 11:11:56 AM

    9/2/2009 11:11:51 AM
    9/2/2009 11:11:59 AM


    哪里有先进先出 分明是并行执行

  38. 韦恩卑鄙
    *.*.*.*
    链接

    韦恩卑鄙 2009-09-02 11:17:00

    用占满cpu 来减少下一个任务完成的效率 哪里是FIFO
    第一个 任务如果是999999次 第二个任务如果是 1次
    第二个任务必然早就结束了

  39. xmanx[未注册用户]
    *.*.*.*
    链接

    xmanx[未注册用户] 2009-09-02 11:27:00

    @韦恩卑鄙
    你测试是正确的,但是代码还是要加入lock,防止
    两个线程中一个访问静态函数,保护静态变量,所以这个文章还有继续讨论的地方

  40. 老赵
    admin
    链接

    老赵 2009-09-02 11:28:00

    @韦恩卑鄙
    这个话题交给你讨论了啊,拜托了,虽然谁想说什么我都可以让他说,但是我不想被扣上“误导初学者”,“做广告”的帽子,也不想看到一个“static方法在单线程情况下会阻塞”的错误观点还坚持是正确的。

  41. 老赵
    admin
    链接

    老赵 2009-09-02 11:30:00

    @xmanx
    所以你“阻塞”的关键是“lock”,别忘了,不是静态方法的问题。
    访问static变量不一定需要lock,例如readonly没有问题。可能有问题的是“并发写”。所以他的代码根本不需要lock。
    而且,我的文章里都写清楚了,FastEvaluator是线程安全的,所以可以同时访问。

  42. xmanx[未注册用户]
    *.*.*.*
    链接

    xmanx[未注册用户] 2009-09-02 11:38:00

    @Jeffrey Zhao
    不要忘记,你书写的代码,效率和内存释放方面也不是写得最优的
    静态的我认为个人理解错误,改正
    你的文章要让看的找不出问题才行,否则就把错误的信息传递给别人,或者不是最好的方式传递给别人

  43. 老赵
    admin
    链接

    老赵 2009-09-02 11:46:00

    @xmanx
    我自然是尽量保证我的做法不会有原则性问题。你觉得哪里不妥当,没问题,可以讨论。
    但是我不接受无端指责,比如什么foreach,什么误导初学者,还怀疑我故意做广告。

    现在,如果你觉得有必要的话,可以谈谈为什么“效率和内存释放方面”不是最优的。
    我的原则是,代码的清晰程度比细枝末节的性能要重要的多。所以我看不出我的代码有什么问题。

  44. xmanx[未注册用户]
    *.*.*.*
    链接

    xmanx[未注册用户] 2009-09-02 11:50:00

    @Jeffrey Zhao
    代码清晰度只是反映给开发人员的
    并不能提高系统的实际运行效率,即使修改了,也不影响你的代码清晰度,修改代码上面已经粘贴过了
    你看不出有什么问题,我看得出问题就可以,一个细小的细节,也可能影响运行效率

  45. 老赵
    admin
    链接

    老赵 2009-09-02 11:53:00

    @xmanx
    你的修改代码,只不过把
    for (var i = 0; i < parameters.Length; i++)

    改成了
    int length = parameters.Length;
    for (var i = 0; i < length; i++)

    你真觉得这个有必要吗?对系统性能有多大帮助?

  46. xmanx[未注册用户]
    *.*.*.*
    链接

    xmanx[未注册用户] 2009-09-02 11:56:00

    Jeffrey Zhao:
    @xmanx
    你的修改代码,只不过把
    for (var i = 0; i < parameters.Length; i++)

    改成了
    int length = parameters.Length;
    for (var i = 0; i < length; i++)

    你真觉得这个有必要吗?对系统性能有多大帮助?



    当然有必要

  47. 老赵
    admin
    链接

    老赵 2009-09-02 11:59:00

    @xmanx
    好吧……

  48. bravf
    *.*.*.*
    链接

    bravf 2009-09-02 12:39:00

    Jeffrey Zhao:
    @xmanx
    好吧……


    one morning in somewhere,lao zhao yao bengkui.haha.

  49. 近近
    *.*.*.*
    链接

    近近 2009-09-02 13:03:00

    表达式树,我没学会,能不能给点简单的例子!复杂了,看不懂!

  50. 近近
    *.*.*.*
    链接

    近近 2009-09-02 13:04:00

    老赵果然是大师级的人物,对于这样的反问,不精通的话,怎么反驳!

  51. 韦恩卑鄙
    *.*.*.*
    链接

    韦恩卑鄙 2009-09-02 15:03:00

    Jeffrey Zhao:
    @韦恩卑鄙
    这个话题交给你讨论了啊,拜托了,虽然谁想说什么我都可以让他说,但是我不想被扣上“误导初学者”,“做广告”的帽子,也不想看到一个“static方法在单线程情况下会阻塞”的错误观点还坚持是正确的。


    你是坏人 NND

  52. 实在看不下去了[未注册用户]
    *.*.*.*
    链接

    实在看不下去了[未注册用户] 2009-09-04 15:27:00


    xmanx

    xmanx:

    Jeffrey Zhao:
    @xmanx
    你的修改代码,只不过把
    for (var i = 0; i < parameters.Length; i++)

    改成了
    int length = parameters.Length;
    for (var i = 0; i < length; i++)

    你真觉得这个有必要吗?对系统性能有多大帮助?



    当然有必要



    本来一直潜水,看、研究老赵的技术文章,今天看到这么一个自以为是的人,实在忍不住了,跳出来说两句。

    这位xmanx,不要想当然,前面的那个访问静态方法会引发阻塞,已经让大家目瞪口呆了,现在又改了一个int length = parameters.Length,自以为改进了不少性能,你自己测试过吗?我随便写了几行代码测试了一下,一亿次的循环,release模式下,数据累加,用i < length和用i < parameters.Length耗时不分上下,很多时候甚至i < parameters.Length还快些,你自己测试一下再说,不要信口开河想当然。另外,这么一点点性能都很看重的话,你绝对应该放弃C#,用asm去写网站好了。

  53. 不骂不痛快[未注册用户]
    *.*.*.*
    链接

    不骂不痛快[未注册用户] 2009-10-10 13:47:00

    xmanx 你个傻逼,二百五...我实在忍不住了...真是不骂不痛快...
    在老赵地盘说粗话了,望老赵见谅...

发表回复

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

昵称:(必填)

邮箱:(必填,仅用于Gavatar

主页:(可选)

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

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

使用Live Messenger联系我