首页 > 代码库 > 程序优化方案(一) 代码优化之异步、多线程、缓存
程序优化方案(一) 代码优化之异步、多线程、缓存
上部分说了代码的合并,那么接下来就说说如何真正的提升程序的速度。这里不得不提到的几个优化程序速度的技术就是异步,多线程和缓存。首先我们要知道程序为什么会卡,特别是加载的时候很慢,原因在于之前的程序是单线程,中途大量的数据库操作和外部接口的调用都耗用了大量的时间导致方法堵塞,所以界面上表现的就是假死状态。
那么异步加多线程加缓存用对地方刚好可以解决这些问题,那么这三种东西都是在什么情况下使用呢。
一、异步
假如现在我们主程序上有一个Grid,当我们在加载的时候这个Grid需要绑定大量的数据,并且根据数据对Grid每行的样式进行修改。传统方法应该是,在加载的时候查询数据库然后给Grid绑定数据源,最后循环Grid根据每列的值改变其样式。在后台处理这些数据的时候,UI线程会一致堵塞,前台界面是假死状态的也就是卡在那里,等待后台处理完成以后前台的界面才会展示数据。一般这个时候我们会采取异步方式来进行后台的数据处理。
下面为不采用异步的方式,运行效果为:等待2秒之后界面和数据显示出来。
namespace WindowsFormsApplication4{ public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { InitDate(); } private void InitDate() { DataTable dt = new DataTable(); dt.Columns.Add("Names"); dt.Columns.Add("Age"); dt.Columns.Add("City"); dt.Rows.Add(new string[] { "d", "2", "2" }); dt.Rows.Add(new string[] { "d", "2", "2" }); dt.Rows.Add(new string[] { "d", "2", "2" }); Thread.Sleep(2000); Grid.DataSource = dt; } }}
下面为异步方式,运行效果为:界面先展示出来在等待两秒之后数据展示,这个时候如果我们在数据加载的过程中加个进度条之类的页面优化是不是用户体验会非常好呢。
namespace WindowsFormsApplication4{ public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { EventInit init = new EventInit(InitDate); this.BeginInvoke(init, null); } delegate void EventInit(); private void InitDate() { DataTable dt = new DataTable(); dt.Columns.Add("Names"); dt.Columns.Add("Age"); dt.Columns.Add("City"); dt.Rows.Add(new string[] { "d", "2", "2" }); dt.Rows.Add(new string[] { "d", "2", "2" }); dt.Rows.Add(new string[] { "d", "2", "2" }); Thread.Sleep(2000); Grid.DataSource = dt; } }}
二、多线程
多线程跟异步的概念有点相似,两者都可以达到避免调用线程阻塞的目的,关于两者的区别,推荐阅读一篇博客园大神的博文 ,文中详细的描述了两者的区别。 http://www.cnblogs.com/DebugLZQ/archive/2012/09/05/2670986.html
那么我们来试一下多线程完成上面的例子。
namespace WindowsFormsApplication4{ public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { // EventInit init = new EventInit(InitDate); // this.BeginInvoke(init, null); Thread thr = new Thread(InitDate); thr.Start(); //if (thr.IsAlive) // thr.Join(); //Grid.DataSource = dt; } delegate void EventInit(); DataTable dt = new DataTable(); private void InitDate() { dt.Columns.Add("Names"); dt.Columns.Add("Age"); dt.Columns.Add("City"); dt.Rows.Add(new string[] { "d", "2", "2" }); dt.Rows.Add(new string[] { "d", "2", "2" }); dt.Rows.Add(new string[] { "d", "2", "2" }); Thread.Sleep(2000); Grid.DataSource = dt; } }}
运行结果,报错如图:,线程间操作无效,MSDN上给出解释:
如果使用多线程处理来提高 Windows 窗体应用程序的性能,则你必须确保以线程安全的方式调用控件。
访问 Windows 窗体控件不是本身就线程安全的。 如果有两个或两个以上线程操作控件的状态,则可能迫使该控件处于不一致状态。 可能出现其他与线程相关的 bug,例如争用条件和死锁。 请务必确保以线程安全的方式访问控件。
同时给出解决方案:使用invoke和 BackGroundWorker 来进行线程的安全调用。代码就不一一贴出来,因为这不是重点,重点是我建议最好在对控件操作的时候不要使用多线程或者尽量少使用多线程,因为经常会有想不到的意外发生,死锁、控件莫名异常等等,不要问我为什么知道,因为我一开始使用的方案就是多线程,后来经常莫名的闪退,程序假死等等奇怪的问题。(其实怪我技术有限,希望大神能有合理的方案)
那么我们到底在什么情况下适合使用多线程呢?首先我们需要知道的前提是:尽量避免对需要共享内存操作的时候使用多线程。比如:在调用第三方的接口初始化的地方、需要耗用大量时间的算法的时候。这些情况下建议使用多线程。线程不要过度使用,第一、会大量消耗CPU资源,第二、程序可控性变差。
三、缓存
这里主要讲的是C#自带的缓存,缓存主要是为了提高数据的读取速度。因为服务器和应用客户端之间存在着流量的瓶颈,所以读取大容量数据时,使用缓存来直接为客户端服务,可以减少客户端与服务器端的数据交互,从而大大提高程序的性能。
适用范围:更新不频繁的表,如字典表或者是一些数据量较大跟新频率较小的表。
注意事项:设置缓存时间,这样可以减小服务器内存压力,并且能较好的同步数据。
推荐博文:http://www.cnblogs.com/anorthwolf/archive/2009/12/07/1618665.html
程序优化方案(一) 代码优化之异步、多线程、缓存