白桦的天空

第一次的心动,永远的心痛!
  首页  :: 新随笔  :: 联系 :: 管理

【转】Windows Mobile 进阶系列——多窗体应用的性能与编程调试1

阅读(13评论(0)发表时间:2009年02月14日 14:22

本文地址:http://qzone.qq.com/blog/84143222-1234592534

本文标签: 窗体 线程 性能 调试 int
摘要:在资源有限的Windows Mobile移动设备上面,具有多窗体的应用程序的性能问题是值得我们去关注的。本文阐述了如何优化多窗体应用程序的性能,提高加载速度的方案以及在性能调试过程中常用的编程调试的技巧
Keywords
Windows Mobile,多窗体,性能,调试,C# 
有朋友说这个系列的前面几篇文章太理论了,不好懂。我很理解,不过我的确得把一些理论性的文章安排在前面,也请筒子们耐心,从现在开始后面的文章会比较轻松一点 J
1.      窗体加载性能
窗体的加载主要是在Form的load事件处理函数里面完成的。所以,我们首先需要尽量使Form_Load里面的代码最小化。把那些负荷比较重的任务放到后台线程上完成,尽量不去阻塞和“耽误”加载窗体的线程。
熟悉.Net Framework的朋友应该知道,.NET Framework2.0以上的版本中引入了一个叫做BackgroundWorker的组件用来实现上述功能。把一些高负荷的工作放到BackgroundWorker组件中去执行,不对主线程造成阻塞。遗憾的是目前在.NET CF中并不支持这个组件,不过你仍然可以使用线程池(Threadpool)来实现类似的功能。
下面的示例,对使用和不使用线程池做同样的任务所用的时间做了比较。
我们先把一个比较重的任务放到主线程上去做:
        private void Form2_Load(object sender, EventArgs e)
       {
//计时起点
            int start = Environment.TickCount;
            int end = 0;
            for (int num = 0; num < 1000; num++)
            {
                this.Text = num.ToString();
            }
//计时终点
            end = Environment.TickCount;
            Debug.WriteLine("Single thread list-populating time (ms) " + (end - start));
        }

所做的工作就是更新form的标题1000次。结果我们可以在output栏看到如下的输出:

可以看到,在Form2的加载过程中,在这样一个任务上(我们仅仅用来模拟某些必不可少的工作)花费了接近1秒钟(916ms)时间。而在这一秒钟时间内,用户是处于等待的状态。显然,这并不是一个好的方案,毕竟在加载Form的时间就让用户等那么久是不厚道的。
下面是使用Threadpool的一个解决方案:
     private delegate void AddDelegate(int num);

        private void Form2_Load(object sender, EventArgs e)
        {
            ThreadPool.QueueUserWorkItem(new WaitCallback(HeavyWork));
        }

        private void HeavyWork (object o)
        {
//计时起点
            int start = Environment.TickCount;

            int end = 0;

            int count = 1000;

            try
            {
                for (int i = 0; i < count; i++)
                {
                    if (this.InvokeRequired)
                    {
                        object[] args = new object[1];
                       args[0] = i;
                        this.BeginInvoke(new AddDelegate(n => { this.Text = n.ToString(); }),args);
                    }
                    else
                    {
                        this.Text = i.ToString();
                   }
                }
            }
            catch(Exception ex)
            {
                Debug.Write(ex.ToString());
            }
//计时终点
            end = Environment.TickCount;
            Debug.WriteLine("Work-thread asynchronize list-populating time (ms) "+ (end - start));
        }



线程池的某一条线程会去执行挂载在WaitCallback 委托上的“等待回调”的HeavyWork方法,并通过Control.BeginInvoke()方法以异步的方式更新Form的标题。我们在output栏中可以看到如下的输出


我们看到,这种利用多线程的异步方式仅花费了169ms,与前面的结果相比,节约了800ms时间。
注意:不同的设备,不同的调试环境所用的时间可能略有不同
当然,并不是非要启用线程的线程池的线程。你完全可以自己创建一条线程做一些额外的工作,或者直接使用AsyncCallBack委托,MSDN上AsyncCallBack的例子很经典,值得大家看一下。不管使用什么方法,我们的目的就在于使用户能最快的看到他想看到的东西,不要让用户对着旋转的光标心叹。