好天气看好电影

魔戒台词:刚铎和洛汉的好男儿,我的好兄弟;我在你们眼中...,看到了我心中也感受到的恐惧;有一天人类将失去勇气...,我们将众叛亲离,一败涂地;但不是今天;有一天邪将胜正,人类的世界也会完全毁灭;但不是今天;今天我们要誓死奋战。为了你们在世上所珍惜的一切...,一定要奋战到底
free hit counter

统计

最新评论

  • 1. re: Invoke and BeginInvoke
  • 哥们,写得太好了,真正的为我解惑了,看了好多文章都云里雾里的,今天终于明白了!
  • --拼命郎
  • 2. re: 三聚氰胺算法
  • @丁学首先说明,我没有造任何谣言。第四题弄错了,1楼纠正了一下,我非常感谢。其它数据都是从网络上取下来,对一个养牛的奶农来说, 就像1楼算出的3吨,或者说1吨有什么区别? 你觉得奶农会一年买几吨或者买...
  • --信息加油站义工
  • 3. re: Invoke and BeginInvoke
  • 受益匪浅
  • --清清爽爽
  • 4. re: 对.net事件的看法
  • 嗯,受教了,不错师傅!
  • --清清爽爽
  • 5. re: 三聚氰胺算法
  • @信息加油站义工
    但是你觉得使用“造谣”的方式对一个中国企业落井下石很好吗?
  • --丁学

提高一下dotnet程序的效率一

 

异常机制

一直以来,有个想法,就是依靠异常机制传递一些信息。如果软件分了层次,或者模块间传递信息,如果采用返回值,就需要定义这些值的含义。例如1代表什么,2代表什么,好一点的话用枚举类型。后来看到有人采用throw机制来传递用户输入的登录凭据不对什么的,就有了一个错误提示信息在层间传递的想法。故而进行一个测试。

protected void Page_Load(object sender, EventArgs e)

        {

            DateTime t = DateTime.Now;

            try

            {

                try

                {

                    TestExption();

                }

                catch(Exception x)

                {

                    throw x;

                }

            }

            catch { }

            DateTime t1 = DateTime.Now;

            Response.Write((t1 - t).TotalMilliseconds);

        }

        protected bool TestExption()

        {

            throw new Exception("ddd");

            return false;

    }

以上测试的结果是,在我的机器:intel duo T7500 2GB内存的配置下,最终得到30多毫秒的结果。

如果没有外面一个try…catch…块,那么得到15多毫秒的结果。

如果去掉throw语句,无论有没有try…catch…,有一个还是两个,得到的都是0毫秒。

看来一个try…catch…块的开销是巨大的,特别是嵌套,更吓人。

我对此测试的原因是质疑,质疑的原因是windows程序的结构化异常捕获的SEH链我比较了解。虽然不知道asp.net是如何实现异常捕获机制的,但是看来开销和SEH链一样的巨大。

我认为异常机制不能用作模块间传递信息的方式,只是在你不知道程序什么时候故障的时候才使用这个机制。例如网络错误,在访问数据库的时候发生了故障等等,这些发生几率很小的地方用异常机制。

如果在web上传递信息的时候采用了异常机制,那么并发量大的情况下,这个开销将是吓人的。

创建对象

这里的计时没法用DateTime了,因为我使用的方法里面也没有一个延时的机制,执行时间小于毫秒级。所以借助了网上一位仁兄的高精度计时器,省得自己去写一个。http://dotnet.chinaitlab.com/ASPNET/742827.html

Ok,下面是我的程序

public class MyClass

    {

        public MyClass()

        {

            menber1 = "";

            menber2 = 0;

            m3 = DateTime.Now;

        }

        protected string menber1;

        protected int menber2;

        protected DateTime m3;

        public int TetsObj()

        {

            return 0;

        }

        public static int TestStatic()

        {

            return 0;

        }

    }

这是被测试的类,有一个静态方法和实例方法。

protected void Page_Load(object sender, EventArgs e)

        {

            MyTimer mt = new MyTimer();

            double t = mt.GetAbsoluteTime();

            MyClass.TestStatic();

            double t1 = mt.GetAbsoluteTime();

            MyClass mc = new MyClass();

            double t2 = mt.GetAbsoluteTime();

            mc.TetsObj();

            double t3 = mt.GetAbsoluteTime();

            Response.Write((t1 - t));

            Response.Write("<br />");

            Response.Write((t2 - t1));

            Response.Write("<br />");

            Response.Write((t3 - t2));

            Response.Write("<br />");

        }

这是测试页面。

下面看输出吧。返回的秒数,也就是多少秒

7.47301692172186E-05
0.000180958753844607
7.9339692092617E-05

这是第一次启动vs2008调试的时候的数据。

1.18730167741887E-06
6.49524008622393E-06
1.25714177556802E-06

第一次刷新的数据。

1.18730167741887E-06
4.74920670967549E-06
1.18730167741887E-06

再次刷新。

2.09523932426237E-06
8.73015960678458E-06
2.09523750527296E-06
again   refresh

2.09523932426237E-06
8.52063567435835E-06
2.16507942241151E-06
again

大概就是这样了。可以看到创建一个对象的时间是调用一个函数的开销的大约4倍以上时间。第一次启动的时候当然这个差距太大了,这是由于object pooling的原因。另外调用静态方法和实例方法的开销一样,如果准确的说,那就是静态方法很多时候更快。

所以,我觉得很多牛人说的没错,创建对象的开销很大,在一个并发很高的web系统里面需要对此进行优化。

测试object    pooling

测试的函数,在MyClass类添加两个方法:

public static void Test1()

        {

            MyClass mc1 = new MyClass();

        }

        public static void Test2()

        {

            MyClass mc1 = new MyClass();

            MyClass mc2 = new MyClass();

        }

        public static void Test3()

        {

            MyClass mc1 = new MyClass();

            MyClass mc2 = new MyClass();

            MyClass mc3 = new MyClass();

    }

页面测试方法:

protected void Page_Load(object sender, EventArgs e)

        {

            MyTimer mt = new MyTimer();

            double t = mt.GetAbsoluteTime();

            MyClass.Test1();

            double t1 = mt.GetAbsoluteTime();

            MyClass.Test1();

            double t2 = mt.GetAbsoluteTime();

            MyClass.Test1();

            double t3 = mt.GetAbsoluteTime();

            MyClass.Test1();

            double t4 = mt.GetAbsoluteTime();

            MyClass.Test2();

            double t5 = mt.GetAbsoluteTime();

            MyClass.Test2();

            double t6 = mt.GetAbsoluteTime();

            MyClass.Test3();

            double t7 = mt.GetAbsoluteTime();

            MyClass.Test3();

            double t8 = mt.GetAbsoluteTime();

            Response.Write((t1 - t));

            Response.Write("<br />");

            Response.Write((t2 - t1));

            Response.Write("<br />");

            Response.Write((t3 - t2));

            Response.Write("<br />");

            Response.Write((t4 - t3));

            Response.Write("<br />");

            Response.Write((t5 - t4));

            Response.Write("<br />");

            Response.Write((t6 - t5));

            Response.Write("<br />");

            Response.Write((t7 - t6));

            Response.Write("<br />");

            Response.Write((t8 - t7));

        }

输出的结果:

首次启动:

0.000266234954324318

1.18730167741887E-06

1.11745976028033E-06

1.11745976028033E-06

0.000111815887066768

1.39682742883451E-06

0.000126622238894925

1.81587165570818E-06

第一次调用Test1(),花费了巨大的时间。再次连续调用三次,花费的时间是大概差不多的,但是与第一次相比相差几个数量级。

然后调用Test2(),比Test1()多创建了一个对象,时间又回到了和第一次差不多,多了几个数量级。

再次调用Test2(),时间又降低了几个数量级。

调用Test3(),又多了一个对象创建,时间又反弹上去了。最后调用Test3(),时间又降低了下来。

Dotnetobject pooling效果由此可见。所以,当一个应用不断地创建对象,并发量大的时候,内存是提高效率的最重要的手段了。内存不是要够,而是要富裕。如果很多对象被Pooling了,效率自然就会提高。

posted on 2008-07-05 17:33 信息加油站义工 阅读(2471) 评论(17)  编辑 收藏 所属分类: 8. 信息技术1. dotnet9. 程序设点滴

评论

#1楼  2008-07-05 17:44 clefoo      

希望LZ提供有些性能优化方面的内容   回复  引用  查看    

#2楼  2008-07-05 17:53 Jeffrey Zhao      

你这个try...catch的试验结论其实也可以这样理解:如果没有抛出异常,try...catch不会影响性能。   回复  引用  查看    

#3楼  2008-07-05 17:58 aoner [未注册用户]

用于编写高性能 Web 应用程序的技巧。但是我并不会将这些建议仅局限于 ASP.NET 应用程序,因为这些应用程序只是 Web 应用程序的一部分。
http://***
  回复  引用    

#4楼  2008-07-05 18:01 新程金锣      

--引用--------------------------------------------------
Jeffrey Zhao: 你这个try...catch的试验结论其实也可以这样理解:如果没有抛出异常,try...catch不会影响性能。
--------------------------------------------------------
如果是这样的话,就没有必要因为害怕性能受影响而放弃这种方式,我感觉用异常来传递错误信息挺方便的。在程序中出错的情况毕竟是少数。   回复  引用  查看    

#5楼 [楼主] 2008-07-05 18:02 信息加油站义工      

@Jeffrey Zhao
对,老赵说得不错。如果没有抛出异常,try...catch不会影响性能。所以,我是建议try...catch要用在异常处理上,而不是对正常的数据输入错误检查之类的地方,这些情况发生的频率比异常要高的多。   回复  引用  查看    

#6楼  2008-07-05 18:25 yuuhhe      

貌似不知道Stopwatch的存在   回复  引用  查看    

#7楼  2008-07-05 20:29 视频聊天 [未注册用户]

来踩你了,脚痒痒。 一脚踩你身体健康二脚踩你万事如意三脚踩你开心快乐!!   回复  引用    

#8楼  2008-07-05 20:31 王弈博      

首先肯定你的严谨的态度,我想说两个问题:

1. 那篇利用异常的文章我看过,其实关于性能的瓶颈始终在数据库层次,CPU、内存操作多花的时间不应该太在意,和数据库比起来是不在一个数量级的。

2.关于后面那个“object pooling效果”的测试,其实结论反映的问题不是什么object pooling机制,而是涉及应用程序域在处理加载一个新方法时初始化分配内存的问题,具体可能涉及垃圾收集机制之类的东西,牵扯的应该是很细节的东西。而“object pooling"应该是代码逻辑层次的概念,.NET底层只能替你优化内存分配之类的东西,而pool object是底层环境无能为力的,是你在代码逻辑上才能处理的。   回复  引用  查看    

#9楼  2008-07-05 20:52 金色海洋(jyk)      

现在的瓶颈在于硬盘的读写速度。   回复  引用  查看    

#10楼  2008-07-05 22:05 Steven Chen      

lz啊
try

{

try

{

TestExption();

}

catch(Exception x)

{

throw x;

}

无论你要干嘛,这个写法,恐怕有些问题吧。
throw x;这句要干什么,一定要清楚哦   回复  引用  查看    

#11楼  2008-07-05 22:06 Gray Zhang      

哈哈我就是那个想用异常胡搞的人
我确实没考虑效率,只是提出了一种理念,因为我认为在OO的方案中,只有异常才可以穿越各层
我相信有一天异常处理会像返回状态码一样高效~   回复  引用  查看    

#12楼 [楼主] 2008-07-05 22:16 信息加油站义工      

@Steven Chen
你可能觉得没人会写这样的异常嵌套,当然初学者也不会。我只是举个例子,其实异常的嵌套是你在不自觉的做的,以前我也经常干。例如:

你在业务层的一个对象方法里面使用了一个try...catch,但是在这个块里面调用了数据层的方法,数据层操作数据库的时候也有try...catch,这样就造成了两重嵌套。如果你的业务逻辑层也throw了捕获到的异常,那么就变成了我的例子。其实,实际的使用中可能造成n重,只是分散到了调用路线的函数里面。   回复  引用  查看    

#13楼 [楼主] 2008-07-05 22:22 信息加油站义工      

@王弈博
非常感谢,你说的很多的东西我很赞同。但是最后一点没能说清楚,应用程序域应该是加载程序集或类型,如果是加载新方法产生了开销,那么我的测试程序其实调用了同一个方法,而不是新方法。只是重复调用同一个类型构造函数,object pooling好像以前了解是dotnet自身的一些机制,而不是我们要在代码逻辑里自己干的事吧?当然架构应用的时候自己干也不错,我测试的应该是dotnet自身的object pooling。当然也没做这方面的深入,请哪位高手指点迷津。   回复  引用  查看    

#14楼  2008-07-06 10:31 zjhjjj [未注册用户]

。NET是没有效率可言的!!!!   回复  引用    

#15楼  2008-07-07 03:22 new 维生素C.net()      

http://www.cnblogs.com/fanweixiao/archive/2008/07/07/1237178.html   回复  引用  查看    

#16楼  2008-07-07 09:53 TONY.chen [未注册用户]

很多时候不应该用到内嵌的TRY CATCH 虽说这样用也是可以的,但是很更多的时候,用一个就够了,原因LZ已经知道了,性能问题   回复  引用    

#17楼  2008-07-07 13:40 A.Z! [未注册用户]

--引用-------------------------------------------------- zjhjjj: 。NET是没有效率可言的!!!! --------------------------------------------------------


写1千字以内的例证,否则直接忽视掉。   回复  引用    


标题  
姓名  
主页
Email (博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2008-07-05 18:09 编辑过


相关链接: