`
窗户纸
  • 浏览: 18285 次
  • 性别: Icon_minigender_1
  • 来自: 北京
最近访客 更多访客>>
社区版块
存档分类
最新评论

面向对象软件开发的后期调优系列之一 : 用好计时器

 
阅读更多

当今社会的程序员聚在一起争论的,往往是哪种开发语言好,于是乎JAVA、C++、c#等等程序员之间必定要掐的一塌糊涂,都觉得自己的好别人的差,(现在貌似C#4.0也开始鄙视C#2.0了,不知何时是个头). 但站在软件开发角度讲,所有程序开发出来的应用都不可避免的面临着后期优化的问题,只要优化得当,各种语言其实都可以达到很理想的执行效率的。

《软件分层开发架构的另一种思考》博文中,我们已经探索了优化的原因及细节。而所用的手段,诸如多线程、异步处理、并发处理、数据缓存应用是各种语言都可以实现的(除了悲催的Javascript),我在此仅以C#做个例子,其实这些方法是放之四海皆可的。

如果一个飞行队要摧毁某个目标,首先做的不是往飞机上装,而是侦查,目标位置在哪里,路径的地形及防御情况如何,目标采用何种才能摧毁等等。对于软件优化也是同样,很多开发小组经常对优化的有效方式摸不到头脑,采用很多方法,越做越差,最后只好回滚。他们往往是采用猜测的方式,比如是不是数据库没加索引表,是不是没有采用异步,需不需要调用外部API等等,于是大手大脚胡改一气。而能够预先了解症结所在,再有针对性的优化,才会是更有效优化的途径。

我们使用的各种调试环境,都有着很丰富的调试工具,诸如变量监视、单步运行、断点、调试堆栈等等等等,但如果要了解特定程序运行过程的各个模块的运行时间,往往要借助我们自己的小工具了。

下面的历程就是我所用的一个简单计时器,该计时器使用singleton模式,只允许一个实例存在,因此可以运行在系统的各个组件中进行同源的检测,检测结果写入日志文件中,这样对于多线程运行环境可以很快了解各个功能点的运行效率,需要注意的是写入日志的过程需要约3ms左右。

public   class T_DebugPerformanceCounter
    {
        [System.Runtime.InteropServices.DllImport("Kernel32.dll")]
        static extern bool QueryPerformanceCounter(ref long count);

        [System.Runtime.InteropServices.DllImport("Kernel32.dll")]
        static extern bool QueryPerformanceFrequency(ref long count);

        public static T_DebugPerformanceCounter FactoryTimer()
        {
            if (_MeTimer == null)
            {
                _MeTimer = new T_DebugPerformanceCounter();
            }
            return _MeTimer;
        }

        //==================================================================
        private static long _Frequency;
        private   long _StartCount;
        private T_DebugPerformanceCounter()
        {
            QueryPerformanceFrequency(ref _Frequency);
            
        }
        private static T_DebugPerformanceCounter _MeTimer;
        public void StartCount()
        {
            QueryPerformanceCounter(ref _StartCount);
        }

        public void PerformCount(string info)
        {
            long count1 = 0;
            double result = 0;              

            QueryPerformanceCounter(ref count1);
            long p = count1 - _StartCount;
            result = (double)(p) / (double)_Frequency*1000;
            UtiltyObj.WriteExceptionToLog(string.Format(info + "耗时: {0} 毫秒", result), System.Diagnostics.EventLogEntryType.SuccessAudit , EventLevel.运行 );
        }        
    }



在实际使用中,我们可以在一个程序入口实例化并启动计时器,然后在合适时候多次记录检测结果,如
....
public void Mytest(int col)
{
T_DebugPerformanceCounter u = T_DebugPerformanceCounter.FactoryTimer();
u.StartCount();
u.PerformCount(string.Format("开始加载列{0}的数据\n", p));
int p = MyFunc1();
u.PerformCount(string.Format("完成加载列{0}的数据\n", p));
}

可以看到,这个计时器非常简单,使用也很容易,它起到的作用却非常大,很多情况下,尤其是多线程编程,影响性能的是最慢的一个分支,如果找不到这一分支,在其他细节上的调整都是徒劳的。

而通过加载了计时器,我们在项目优化中发现了一个有趣的现象,初期绝大部分的性能问题来自系统的BUG,而不是数据库存取、装箱拆箱等我们认为会影响性能的地方。


分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics