优化Visual Basic应用程序(仅供参考)---2001年《电脑报》第24期

目前的硬件条件比起前些年虽然已有了很大的改善,但应用程序的性能仍然受到处理器速度、内外存空间及网络连接等诸多因素的制约,为了在有限的硬件资源的前提下,尽可能地提高应用程序的效率和性能,必须在设计和编写应用程序时缩小应用程序的大小、提高计算和显示的速度,进而优化所创建的应用程序。
程序的优化大体上可以分为两种:时间上的优化和空间上的优化(本文把这两种优化分别称为“速度优化”和“大小优化”)。下面,笔者从这两个方面谈谈对Visual Basic应用程序的优化方法。
一、速度的优化
在用户评测应用程序是否满意的诸多因素中,速度是决定性的因素。所以,有必要优化创建的应用程序,加快其速度。
程序的速度可以分为三种:真实速度(执行代码的实际时间)、显示速度(屏幕显示的时间)和感觉速度(应用程序运行时的感觉速度)。
1、真实速度的优化
为了加快Visual Basic程序的真实速度,使代码计算或运行的更快,可采用以下的几种技术
(1).避免使用 Variant 变量
Variant(变体型)变量是Visual Basic的缺省变量类型,程序中凡是未加类型说明的变量均认为是变体型变量,使用这种变量对于初学者以及处理速度不成问题的应用程序来说,是非常方便的。然而,如果想提高应用程序的实际速度,就要避免使用变体型变量。因为,在运行时Variant将转化为其它适当的数据类型,而转化的过程是需要时间的。如果直接采用其它简单的数据类型,就可以避免不必要的类型转换操作而加快应用程序的速度。
避免使用Variant变量的好办法是让Visual Basic自动地在每个模块前加上Option Explicit 语句,这样所有的变量在使用前都必须进行声明。方法是:在“工具”菜单中启动“选项”对话框,选择“编辑器”选项卡,选定“要求变量声明”复选框,该设置对之后所有新建的模块起作用。
有一点需要注意,由于Visual Basic的变量声明可以不定义变量类型,所以即使经过了声明,如果未加类型限制,也会产生Variant变量。
特别是在声明多个变量时要小心,Visual Basic有一个“怪癖”,它无法在一条声明语句中仅使用一个As type来同时说明多个该类型的变量,在下面的例子中,Z被声明成Long型,而X和Y是仍是Variant变量:
Dim X, Y, Z As Long
为了将X和Y也声明成Long型变量,需重写语句如下:
Dim X As Long, Y As Long, Z As Long
(2).选用最佳的数据类型
程序中要尽量避免使用Currency、Single和Double变量,并尽量使用Long整型变量,尤其在循环体中。因为Long整数是32位CPU的本机数据类型,所以其操作非常快。如果无法使用 Long 变量,就要尽量使用Integer或Byte数据类型。很多时候,即使在要求使用浮点数的情况下,也可以使用 Long 整数。例如,在窗体和图形控件的 ScaleMode 属性设置为缇或象素时,就可以在控件和图形方法中使用Long整型变量表示大小和位置。
进行除法运算时,结果如果不需要小数部分,就可以使用整数除法运算符 (/)。由于浮点运算需要转移到协处理器上进行,而整数运算并不需要,所以整数运算总是比浮点运算快。如果确实需要做小数运算,则应选取相对较快的数据类型。在Visual Basic中各种数值数据类型的
***************值得推敲**********************
运算速度顺序如下(由快到慢):
Long->Integer->Byte->Single->Double->Currency


*****************************************************


(3).将常用的属性值、函数返回值缓存在变量中
一般来说,变量的处理速度比同类型的属性处理速度快许多,因此如果经常用到某一属性的值(如在循环体中),应该先将该属性值赋给某一变量,以后用该变量替代该属性,这样就能够提高代码的速度。例如,象这样的代码就比较慢:
For i = 0 To 10
label(i).Left = text1.left
Next i
下面改写的代码就要快得多:
LabelLeft = text1.left
For i = 0 To 10
label(i).Left = LabelLeft
Next i
同样的技术可用于处理函数的返回值,用变量缓存函数的返回值,避免经常调用运行时的动态链接库,也会大幅度地提高速度,如:某程序中多次用到Mid(Text1.text),则可先用一变量TempString保存Mid(Text1.text)的值,之后凡是用到该函数的地方一律用TempString代替。
(4).使用内嵌过程替代过程调用
采用过程调用使代码更具有模块化的风格,但过程调用总是增加额外的操作和处理时间。如果循环体中多次调用某一过程,就可以直接把该过程写到循环体中去,以消除过程调用时的额外负担。
但另一方面,直接把某一过程写到好几个循环体中时,重复的代码无疑要增加应用程序的大小;同时,在更改程序时,有可能忘记更改这些重复的代码,这就增加了出错的机会。因此,在使用内嵌过程时要仔细权衡利弊。
(5).尽可能使用常数
使用常数是一项非常好的编程习惯,常数不仅可以加快应用程序的运行,而且还可增强代码的可读性,使之易于维护。如果代码中的字符串或数字是不变的,则可把它们声明为常数。常数是在编译时进行处理的,编译程序用适当的值替换代码中常量,而变量在每次运行时都要读取当前值。


**************值得推敲*******************************
(6).尽量用ByVal传递参数,而不用ByRef
编写含参数的Sub或Function时,按值(ByVal)传递参数比按地址(ByRef)快。尽管 Visual Basic中参数传递的缺省方式是ByRef,但实际上需要改变参数值的过程极少(ByRef的目的就是为了允许在过程中改变参数的值)。如果过程中不需改变参数的值,就可以按值(ByVal)来传递,ByVal的用法如下:
Private Sub DoSomething(ByVal AuthorName As String)


******************************************************************


(7).正确地选择集合和数组
如果多个对象的类型一样,集合或数组都可以用来管理这些对象(如果对象的类型不一样,则只能用集合)。从速度的观点看,选择何种方式取决于对象的访问方式。如果能够为每一对象分配唯一的关键字(如Name属性),则集合是访问对象的最快方式。。而对顺序遍历方式而言,数组比集合快,所以当没有关键字而要遍历对象时,则选择数组比较好。
****************值得推敲***************
(8).尽量少用点操作
当从Visual Basic中引用其它应用程序的对象时,可使用点语法“.”对对象的集合、属性和方法等进行应用。然而每一个“点”都需要Visual Basic产生多次调用,因此为了写出最有效的应用程序,引用对象时应尽量少使用多余的点操作。以下的方法可减少“点”的使用。
a.使用缺省的方法和属性
当对象使用缺省的方法或属性时,可以省略该方法或属性,也就减少了一次“点”的使用,如:
Label1 = Text1
在功能上相当于:
Label1.Caption = Text1.Text
但确减少了“点”的使用次数。
**************************************************************

b.使用Set语句
Set语句可缩短定位字符串,并提供对代码更灵活的控制。下例使用Dim和Set语句创建变量,使其引用经常使用的对象:
Dim xlRange As Object
Set xlRange = Application.ActiveSheet.Cells(1,1)
xlRange.Font.Bold = True
xlRange.Width = 40
c.使用With...End With
利用Visual Basic提供的With...End With语句,不仅可以大大地减少“点”的使用,同时还使代码简洁易读。如上例可改写为:
With Application.ActiveSheet.Cells(1,1)
.Font.Bold = True
.Width = 40
End With
2、显示速度的优化
在Windows的图形环境下,加快图形和其它操作的显示速度对整个程序的速度的提高起非常重要的作用。以下的几种技术可用来提高应用程序的显示速度:
(1).将容器的ClipControls属性设置为False
如果不使用图形方法(Line,Pset,Circle 和 Print等),就可以将窗体、框架及PictureBox控件的ClipControls属性设置为 False。这样在重画控件本身之前,Visual Basic不会用背景覆盖控件,这在窗体包含大量控件时,会大大提高显示速度。
(2).恰当地使用AutoRedraw
当窗体或控件的 AutoRedraw属性设置为True时,Visual Basic会利用位图重画该窗体或控件。这种方法虽然提高了简单情况的重画速度,但会降低图形方法的速度。
如果应用程序产生的图形复杂但是不常改变,AutoRedraw设置为True 较为合适。如果图形需要经常改变,则AutoRedraw设置为False的效果更好。
(3).用Image控件替代PictureBox控件
PictureBox控件比Image控件的功能要强,如提供了图形方法、包含其它控件的能力或动态数据交换 (DDE)能力,因此它的处理时间也相对Image控件较长。如果仅简单显示图片,或只对简单的鼠标操作作出响应,则应使用Image控件替代 PictureBox。
(4).设置属性时隐藏控件以避免多次重画
重画的代价是昂贵的,重画操作越少,应用程序就越快。减少重画次数的一种方法,就是在改变控件属性时使其不可见。例如,假设在窗体的Resize事件中调整数个列表框的大小:
Sub Form_Resize ()
Dim i As Integer, sHeight As Integer
sHeight = ScaleHeight / 4
For i = 0 To 3
lstDisplay(i).Move 0, i * sHeight, ScaleWidth, sHeight
Next
End Sub
上面的代码产生四次独立的重画,每个列表框一次。可以把所有的列表框放在一个图片框中,并在移动或调整列表框大小之前隐藏图片框,就会减少重画的次数。当再次使图片框可见时,所有的列表框一次画出,修改后的代码如下:
Sub Form_Resize ()
Dim i As Integer, sHeight As Integer
picContainer.Visible = False
picContainer.Move 0, 0, ScaleWidth, ScaleHeight
sHeight = ScaleHeight / 4
For i = 0 To 3
lstDisplay(i).Move 0, i * sHeight, ScaleWidth, sHeight
Next
picContainer.Visible = True
End Sub
在上面的两段代码中还显示了另外一种减少重画次数的技巧,即使用Move方法替代设置Top和Left属性。Move方法只需一次操作就设置了这两个属性,所以节省了多余的重画。
3、感觉速度的优化
通常,应用程序的感觉速度和代码的实际执行速度并无多大关系。对用户来说,启动快、绘画快并提供不间断的反馈信息的应用程序显得速度快;而在完成任务时似乎“悬挂”起来的应用程序则显得速度慢。许多技术都可以使应用程序显得速度快:
(1).隐藏窗体而不加载
在暂时不需要某个窗体时,把它隐藏起来而不是把它们卸载,是一项提高显示速度和感觉速度的非常有效的技巧,这样当再次需要该窗体时,不需要额外的时间去加载窗体,只需简单地使用Show方法即可。这项技术的负效应是要占用一定的内存。但如果能够提供足够的内存,而且窗体能够快速出现被认为是最重要的,则可以采用这项技术。
(2).预加载数据
预先读取数据也可以改善应用程序的感觉速度。例如,需要从磁盘上加载某个文件时,可以顺便加载其它后面会用到的文件,加载额外的文件增加的时间也许并不会被觉察到,而且以后不会再次出现延迟。
(3).使用进度指示器和等待光标
如果程序中存在不可避免的长时间延迟,则必须给用户以提示,说明应用程序并没有悬挂起来。可以使用标准的进程指示控件ProgressBar来提示用户,至少也应设置窗体的MousePointer属性为vbHourglass(11),这样就会显示等待光标来表明程序正在运行。
(4).加快应用程序的启动速度
用户对应用程序的印象好坏往往取决于程序的启动速度,因此应尽可能地加快程序的启动速度。可以使用以下两种方法提高启动速度:
a.简化启动窗体
窗体越复杂,其加载的时间就越长,所以要使启动窗体尽量简单。启动窗体上的控件越少,包含的代码越少,则其加载和出现的速度就越快。可以在应用程序启动时先显示一份简洁的版权屏幕,然后再加载其它更复杂的窗体(这时,可利用进度条),这样当启动版权屏幕时,用户已知道应用程序已经启动。
b.不要加载不需要的模块
Visual Basic根据要求加载代码模块,只有调用了某模块中的过程时,才会加载该模块,未被调用的模块不会被加载。如果启动窗体调用了数个模块中的过程,则应用程序启动时将加载所有这些模块,这就会降低速度。所以应避免从启动窗体中调用多个模块的过程,换句话说,就是应该将启动窗体所有调用的过程放在一个模块中,这样启动时只需加载一个模块。
二、大小优化
缩小应用程序的大小不仅可以节约系统资源(减少内外存的占用),同时由于较小的应用程序加载的速度较快也可能带来速度的提升,因此,也应对程序的大小进行优化。
1、减少加载窗体的数目
每一个加载的窗体,无论可视与否,都要占据一定数量的内存(其数量随窗体上控件的类型和数量,以及窗体上位图的大小等的不同而变化)。只在需要显示时才加载窗体,不再需要时,卸载窗体(而不是隐藏窗体)。卸载窗体最好的办法不是Unload,因为Unload只能释放部分窗体所占空间,要释放所有空间,可用关键字Nothing使窗体的引用无效:
Set Form = Nothing
非常遗憾的是,这一条减少内存占用的原则与上述加快速度的原则相抵触,具体采用哪一种优化,需根据具体情况而定。
2、减少控件数目
当设计应用程序时,窗体应尽量少用控件,含有大量控件的窗体将运行缓慢。必须使用许多控件时,也应尽可能地使用控件数组,而不是在窗体上放置大量同类型的控件。
3、用标签代替文本框
标签控件占用的 Windows 资源比文本框少,因此,在可能的情况下,应使用标签代替文本框。例如,当窗体上需要一个隐藏的控件保存文本时,使用标签更有效。
4、保持数据在磁盘文件或资源中,并且只在需要时才加载
在设计时,直接放入应用程序的数据(象属性或代码中的文字字符串和数值)将增加运行时应用程序占用的内存。运行时从磁盘文件或资源中加载数据可减少占用内存。特别是对图形、图象和大的字符串更是如此。
5、组织模块
前面已经提到,将相关的过程放在同一模块中可加快程序的启动,这条原则也同样用于减少内存的占用。尽量把相关的过程放在同一模块,让Visual Basic只在需要时才加载其它模块,这样可避免加载无用(至少是暂时无用)的模块,以达到减少内存占用的目的。
6、使用简单的数据类型
简单数据类型,不仅运行速度较快,其占用的内存也少,因此,应尽量使用简单的数据类型,特别要少使用Variant的变量数组,因为变体型数据占用的内存远大于其它类型数据。
但要注意,在有些情况下,使用其它数据类型替代Variant,灵活性降低了,为弥补损失的灵活性,不得不增加更多的代码。结果是程序的大小不仅没有减少反倒是增加了,要避免这种得不偿失的做法。
7、使用动态数组
使用动态数组代替固定数组可以节省内存占用,需要时,还可用Erase删除动态数组或ReDim Preserve减少数组大小。而对于固定大小的数组,是无法将其所占的内存收回的(除非数组的生命周期结束)
8、消除死代码和无用的变量
在开发和调试应用程序时,可能遗留了死代码(绝对不可能执行到的代码),也可能声明了一些无用的变量。注意要复查代码,查找并删除无用的变量和死代码。
当然,就像绝大多数语言一样,Visual Basic在编译时忽略注释语句,所以没有必要删除注释语句。
9、用Image控件代替PictureBox控件
这是另一项既优化速度,又优化大小的技术。正如前文所述,当不需要使用Picture 控件的特殊功能时,可用Image控件代替PictureBox控件,这样可以节省大量的系统资源。
10、共享图片
如果在设计时将相同的图片加载到几个窗体或控件中,每一个窗体或控件都存储了该图片的一个副本。然而如果将图片存于一个窗体中,而让其它窗体或控件共享该图片,这样既可减少程序的大小(因为不包含冗余的图片拷贝)又可加快速度(因为不必从磁盘中多次加载)。如下面的代码:
Picture = LoadPicture("C:WindowsChess.bmp")
Image1.Picture = Picture '使用相同的图片。
Picture1.Picture = Picture '使用相同的图片。
比下列加载了同一位图的三个副本的代码要好得多。
Picture = LoadPicture("C:WindowsChess.bmp")
Image1.Picture = LoadPicture("C:WindowsChess.bmp")
Picture1.Picture = LoadPicture("C:WindowsChess.bmp")
以上,笔者就Visual Basic程序的优化介绍了一些常用的技巧,由于影响应用程序性能的因素非常多,所以对程序的优化要远比上述情况要复杂得多,欢迎广大读者就程序的优化提出自己独特的见解。

posted on 2010-12-18 13:48  rooly  阅读(362)  评论(0)    收藏  举报