现在的位置: 首页 > 综合 > 正文

提高一下dotnet程序的效率一

2011年01月09日 ⁄ 综合 ⁄ 共 4721字 ⁄ 字号 评论关闭
 

异常机制

一直以来,有个想法,就是依靠异常机制传递一些信息。如果软件分了层次,或者模块间传递信息,如果采用返回值,就需要定义这些值的含义。例如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了,效率自然就会提高。

抱歉!评论已关闭.