重拾VB630:Designing for Performance and Compatibility

来自MSDN-2001-OCT: Visual Tools and Languages/Visual Studio 6.0 Documentation/Visual Basic Documentation/Using Visual Basic/Programmer’s Guide/Part 2: What Can You Do With Visual Basic/Designing for Performance and Compatibility/

1. Understanding Optimization

(1) Knowing What to Optimize: Understanding the Real Problem;

(2) Knowing Where to Optimize: Maximum Benefit with Minimum Effort; For example,if speed is your primary goal,the bodies of loops are usually a good place to start. The same principle applies to frequently called subroutines as well.

(3) Knowing When to Stop: Weighing the Results;

Sometimes things aren't worth optimizing. For example,writing an elaborate but fast sorting procedure is pointless if you're only sorting a dozen items. It’s possible to sort things by adding them to a sorted list box and then reading them back out in order. With large numbers of items this is horribly inefficient,but if there aren't a lot of items it is just as quick as any other method,and the code is admirably simple (if a bit obscure).

There are other cases where optimization is wasted effort. If your application is ultimately bound by the speed of your disk or network,there is little you can do in your code to speed things up. Instead you need to think about ways to make these delays less problematic for your users: progress bars to tell them your code isn't simply hung,caching data so they see the delays less often,yielding so that they can use other programs while they wait,and so on.

2. Optimizing Code

(1) Avoid Using Variant Variables: Because Visual Basic converts Variants to the appropriate data type at run time,operations involving other simple data types eliminate this extra step and are faster than their Variant equivalents.

(2) Use Long integer variables and integer math. For arithmetic operations avoid Currency,Single,and Double variables. Use Long integer variables whenever you can,particularly in loops. The Long integer is the 32-bit CPU's native data type,so operations on them are very fast; if you can’t use the Long variable,Integer or Byte data types are the next best choice.

When performing division,use the integer division operator (/) if you don’t need a decimal result. Integer math is always faster than floating-point math because it doesn’t require the offloading of the operation to a math coprocessor. If you do need to do math with decimal values,the Double data type is faster than the Currency data type.

Numeric data types Speed
Long Fastest
Integer
Byte
Single
Double
Currency Slowest

(3) Cache Frequently Used Properties in Variables: Variables are generally 10 to 20 times faster than properties of the same type.

Caching function return values avoids frequent calls to the run-time dynamic-link library (DLL),Msvbvm60.dll.

(4) Use Module-level Variables Instead of Static Variables: 酱紫虽然快但是你得自己保证只有一个过程或函数可以改这个模块级变量。The tradeoff here is that your code will be less readable and harder to maintain.

(5)Replace Procedure Calls with Inline Code. 在循环中这会提高性能,但是会让你的代码变大,而且如果你在多个地方调用的话,可维护性降低(因为你需要在多个地方同时update它)。

Likewise,calling a procedure that resides in the same module is faster than calling the same module in a separate .BAS module; if the same procedure needs to be called from multiple modules this gain will be negated.

(6)Use Constants Whenever Possible: Constants are resolved once when your program is compiled,with the appropriate value written into the code. With variables,however,each time the application runs and finds a variable,it needs to get the current value of the variable.

Whenever possible,use the intrinsic constants listed in the Object Browser rather than creating your own. You don’t need to worry about including modules that contain unused constants in your application; when you make an .exe file,unused constants are removed.

(7)Pass Unmodified Arguments with ByVal Instead of ByRef

(8)Use Typed Optional Arguments: The typed optional arguments are faster to access than Variants,and as a bonus,you'll get a compile-time error message if you supply information of the wrong data type.

(9)Take Advantage of Collections

a) Use For Each...Next rather than For...Next. 因为后者的实现是最简单的线性的,而前者通常会用稍高级些的算法。

b) Avoid using Before and After arguments when adding objects to a collection. Those arguments require Visual Basic to find another object in the collection before it can add the new object.

c) Use keyed collections rather than arrays for groups of objects of the same type. If you can associate a unique key with each object,then a collection is the fastest choice; If not,Arrays are faster to traverse sequentially than collections.

For small numbers of objects,arrays use less memory and can often be searched more quickly. The actual number where collections become more efficient than arrays is around 100 objects; however,this can vary depending on processor speed and available memory.

(10) You can also optimize your application by increasing data access speed.

3. Measuring Performance

(1) 基本做法:在一个循环里多次运行你要测试的算法,用timer记录开始和结束时间。

(2) You may need to experiment with different values for the upper bounds of the loop counter,especially for fast routines. Make sure that you run each version several times to get an average; results can vary from one run to the next.

4. Optimizing Display Speed

(1) Set the ClipControls Property of Containers to False. When ClipControls is False,Visual Basic doesn’t overpaint controls with the background before repainting the controls themselves. On forms that contain a lot of controls,the resulting speed improvements are significant.

(2) Use AutoRedraw Appropriately.

If your application generates complex graphics but doesn’t change them frequently,setting AutoRedraw to True is appropriate. But if your application draws graphics that must change frequently,you will get better performance if you set AutoRedraw to False and perform the graphics methods for the form or control in the Paint event.

(3) Use Image Controls Instead of Picture Box Controls

Don’t use a picture box unless you need the capabilities only the picture box provides,such as graphics methods,the ability to contain other controls,or dynamic data exchange (DDE).

(4) Hide Controls When Setting Properties to Avoid Multiple Repaints

Every repaint is expensive. The fewer repaints Visual Basic must perform,the faster your application will appear.

One way to reduce the number of repaints is to make controls invisible while you are manipulating them.

(5)Use Line Instead of PSet

Avoid using the PSet method and batch up the points into a single Line method. Shape and line controls are appropriate for simple graphical elements that rarely change; complex graphics,or graphics that change rapidly,are generally best handled with graphics methods.

5. Optimizing Perceived Speed

(1) Keep Forms Hidden but Loaded: Hiding forms instead of unloading them. The obvious downside to this technique is the amount of memory the loaded forms consume,but it can't be beat if you can afford the memory cost and making forms appear quickly is of the highest importance.

(2) Preload Data: 趁用户不注意的时候偷偷preload some data.

(3) Use Timers to Work in the Background: 等待用户输入的时候,在timer事件里偷偷干点活。

(4) Use Progress Indicators.

Use DoEvents at strategic points,particularly each time you update the value of the ProgressBar,to allow your application to repaint while the user is doing other things.

At the very least,you should display the wait cursor to indicate the delay by setting the form’s MousePointer property to vbHourglass (11).

6. Speed the Start of Your Application

(1) With the various run-time DLLs that need to be loaded for Visual Basic for Applications,ActiveX controls,and so forth,some delay is unavoidable with any application.

(2) Use Show in the Form_Load Event

Sub Form_Load()
Me . Show ' Display startup form.
DoEvents ' Ensure startup form is painted.
Load MainForm ' Load main application fom.
Unload Me ' Unload startup form.
MainForm . Show ' Display main form.
End Sub

(3) Simplify Your Startup Form

可以先display a splash screen

如果需要加载许多其他窗体,可以display a progress bar in your startup form and update it as you load each of the other forms. Call DoEvents after loading each form so that your startup form will repaint. Once all the important forms have been loaded,the startup form can show the first one and unload itself.

(4) Don’t Load Modules You Don’t Need

Visual Basic loads code modules on demand,rather than all at once at startup. This means that if you never call a procedure in a module,that module will never be loaded. You should therefore avoid calling procedures in other modules from your startup form.

(5) Run a Small Visual Basic Application at Startup to Preload the Run-time DLLs.

A large part of the time required to start a Visual Basic application is spent loading the various run-time DLLs for Visual Basic,ActiveX,and ActiveX controls. Of course,if these are already loaded,none of that time need be spent. Thus users will see your application start up faster if there is another application already running that uses some or all of these DLLs.

For example,you might write a small application to display a calendar and install it in the startup group for Windows. It will then load automatically on system startup,and while it is useful in itself,it also ensures that the various Visual Basic run-time DLLs are loaded.

也可以divide your application into a main skeleton application and several component executables or DLLs. A smaller main application will load faster,and it can then load the other parts as needed.

7. Reducing Code Size (通常也就意味着减少对内存的占用)

(1) 不会影响代码大小的因素:Identifier names,Comments,Blank lines. None of these elements affect the size of your application in memory when it is running as an .exe file. Visual Basic takes care of all these.

(2) Reduce the Number of Loaded Forms. Each loaded form,whether visible or not,consumes a significant amount of memory.

When you unload a form using the Unload method,only a portion of the memory occupied by the form is released. To free all memory,invalidate the reference to the form by using the Nothing keyword: Set Form = Nothing

(3) Reduce the Number of Controls: A related technique is to use control arrays where possible,rather than putting a large number of controls of the same type on a form at design time.

(4) Use Labels Instead of Text Boxes: Label controls use fewer Windows resources than text boxes do,so you should use labels in place of text boxes whenever possible.

Even a data entry form that requires numerous text fields can be optimized using this technique. You can create a label for each field and use a single text box for input,moving it to the next label's location in the LostFocus event (真够累的哦):

Private Sub Label1_LostFocus()
' Update Label1
Label1 . Caption = Text1 . Text
' Move the Textbox over the next label
Text1 . Move Label2 . Left , Label2 . Top
' Update Text1 contents
Text1 . Text = Label2 . Caption
End Sub

(5) Keep Data in Disk Files or Resources and Load Only When Needed.

Data you place directly into your application at design time (as properties or as literal strings and numbers in your code) increases the memory the application consumes at run time. You can reduce memory by loading the data from disk file or resources at run time. This is particularly valuable for large bitmaps and strings.

(6) Organize Your Modules. Placing related procedures in the same module causes Visual Basic to load modules only as needed.

(7) Consider Alternatives to Variant Data Types

Each Variant takes 16 bytes,compared to 2 for an Integer or 8 for a Double. Variable-length String variables use 4 bytes plus 1 byte per character in the string,but each Variant containing a string takes 16 bytes plus 1 byte per character in the string. Because they are so large,Variant variables are particularly troublesome when used as local variables or arguments to procedures,because they quickly consume stack space.

In some cases,using other data types forces you to add more code to compensate for the loss of flexibility that the Variant data type provides,resulting in no net reduction in size.

总之,Variant是又占地方效率又不高可维护性也差。

(8) Use Dynamic Arrays and Erase to Reclaim Memory. Erase recovers no memory for fixed-size arrays. Erase frees the memory used by dynamic arrays.

Erasing a fixed-size array will not reclaim the memory for the array — it simply clears out the values of each element of the array. If each element was a string,or a Variant containing a string or array,then erasing the array would reclaim the memory from those strings or Variants,not the memory for the array itself.

(9) Reclaim Space Used by Strings or Object Variables. 局部变量会立刻释放,但是全局变量会始终存在,If you are trying to keep your application as small as possible,you should reclaim the space used by these variables as soon as you can.

You reclaim string space by assigning the zero-length string to it

you can reclaim some (but not all) of the space used by an object variable by setting it to Nothing.

You can also reclaim space by unloading forms and setting them to Nothing rather than simply hiding them when they are no longer needed. 不过只hide的话,运行起来会比较快。

(10) Eliminate Dead Code and Unused Variables: 清掉从来不用的代码和变量。Although Visual Basic does remove unused constants,it does not remove unused variables and dead code when you create an .exe.

另外debug.print虽然会被忽略,但是如果它里面包含的有function call,那么the Debug.Print statement itself is ignored by the compiler,but the function call is compiled. Then,when the application is run,the function is called but the return is ignored.

8. Cutting Back on Graphics

(1) 一幅图胜过千言万语,但是它们can consume a lot of memory.

(2) Use the Image Control to Display Bitmaps: The image control is a "lightweight" control rather than a window and doesn't use nearly as many resources. In fact,you can typically use five to 10 times as many image controls as picture controls. Moreover,image controls repaint faster than picture controls. Only use a picture controls when you need a feature only it provides,such as dynamic data exchange (DDE),graphics methods,or the ability to contain other controls.

(3) Load Bitmaps from Files As Needed and Share Pictures

When you set a Picture property at design time,you add the picture to the form and thereby increase the memory the form consumes at run time. You can reduce memory consumption by storing pictures in a resource file and using the LoadResPicture function to load them at run time.

You can share the same picture between multiple picture controls,image controls,and forms. If you use code like this you only maintain one copy of the picture:

Picture = LoadPicture( "C:/Windows/Chess.gif")
Image1 . Picture = Picture ' Use the same picture.
Picture1 . Picture = Picture ' Use the same picture.

Contrast that with this code,which causes three copies of the bitmap to be loaded,taking more memory and time:

Picture = LoadPicture( "C:/Windows/Chess.gif")
Image1 . Picture = LoadPicture( "C:/Windows/Chess.gif")
Picture1 . Picture = LoadPicture( "C:/Windows/Chess.gif")

This makes your application both smaller (because it doesn't contain redundant copies of the picture) and faster (because the picture doesn't have to be loaded from disk multiple times).

(4) Use the PaintPicture Method

Rather than placing bitmaps in controls,you can use the PaintPicture method to display bitmaps anywhere on forms. This is particularly useful when you want to tile a bitmap repeatedly across a form: You only need to load the bitmap once,but you can use PaintPicture to draw it multiple times.

(5) Free the Memory Used by Graphics

When you are no longer using a picture in the Picture property of a form,picture box,or image control,set the Picture property to Nothing to empty it

If you use the Image property of a picture box or form,Visual Basic creates an AutoRedraw bitmap (even if the AutoRedraw property for that form or picture box is False). When you have finished using the Image property,you can reclaim the memory used by this bitmap by using the Cls method before setting AutoRedraw to False.

(6) Use Rle-Format Bitmaps or Metafiles

Rle bitmaps can be several times smaller than their uncompressed counterparts,particularly for bitmaps that contain large swatches of solid color,and they aren't appreciably slower to load or display.

Using metafiles (.wmf) can produce even greater savings — 10 times or more in some cases. Try to use metafiles at their normal size: They are much slower to paint when they have to be stretched larger or smaller.

You can also use .gif and .jpg formats. They are generally much smaller; however there is some tradeoff in image quality and loading speed.

9. Segmented Applications

(1) you can write an application that consists of a core front-end executable supported by a number of ActiveX components. This approach offers several significant optimization benefits:

a) The components are loaded on demand and can be unloaded when no longer needed.

b) Cross-process components can be 32-bit executables on Windows 95,Windows 98,or Windows NT,even if other parts of the application are 16-bit components.

c) Remote components can use the resources of other machines on the network.

(2) There are three kinds of components you can create with the Professional or Enterprise editions of Visual Basic: Cross-process,In-process,Remote. These three kinds are not exclusive: You could use all three in a single application.

(3) Cross-Process Components

A cross-process component is an executable program that offers its services to other programs. Like all executables,it starts up and runs with its own stack in its own process space; thus,when a application acting as a client uses one of the objects provided by a component,the operation crosses from the client's process space to the component's — hence the name.

优点1:Asynchronous operation ("threads"). This is particularly useful when your application needs to perform some operation that takes a long time. The client can call the component to perform the operation and then continue responding to the user.

优点2:Interoperability between 16-bit and 32-bit applications. This allows you to incrementally take advantage of 32-bit features and performance while preserving your investment in 16-bit components

优点3:Untrapped errors in the component won't cause the calling application to crash.

缺点1:A cross-process component will always be slower to start than an in-process component

缺点2:Every interaction with the component is a cross-process call. Crossing process boundaries takes a lot of CPU cycles. So every reference to an object from the cross-process component is much more expensive than an equivalent reference to an object in the client application itself or an in-process component. Reducing the number of cross-process calls in your code can reduce the impact of the cross-process call overhead.

(4) In-Process Components

With an in-process component,no new process needs to be created and no run-time DLLs need to be loaded. This can make an in-process component considerably quicker to load compared to an equivalent cross-process component.

Because it is in-process,there is no cross-process overhead when referring to the methods or properties on an object supplied by the component. Objects from the component operate with the same efficiency as objects within the client application itself.

(5) Remote Components

Although network overhead will inevitably exact a toll on application performance,you can make up for it by using the resources of additional CPUs.

This is particularly true when you work with a remote component that is operating on data that is local to the machine containing the component. Since this data would have to be fetched across the network anyway,a component operating on it locally and returning only the results across the network can actually be more efficient.

10. Optimizing Objects

(1) Early Binding vs. Late Binding

Early binding enables Visual Basic to do most of the work of resolving the definition of the object at compile time rather than at run time,when it impacts performance.

Late binding objects is expensive: At compile time you get no error checking,and each reference at run time requires at least 50% more work by Visual Basic.

(2) Minimize the Dots

When calling an object from Visual Basic,each "dot" requires Visual Basic to make multiple calls.

(3) Use Set and With...End With

(4) Minimize Cross-Process Calls

If possible,do not reference objects inside a For...Next loop. Cache values in variables and use the variables in loops.

If you have to call a large number of methods on an object,you can greatly improve the performance of your application by moving the code into the component. For example,if the component is Word or Microsoft Excel,you can put a looping macro in a template in Word or a looping procedure into module in Microsoft Excel. You then call the macro or procedure from Visual Basic,which is a single call that launches a looping operation within the component.

If you are writing components,when you have several interrelated properties,implement a method with several arguments — one for each property. Calling the method requires a single cross-process call regardless of how many arguments it has,whereas setting each property requires a separate cross-process call.

Likewise,if you anticipate that the component acting as a client will want to call your component in a loop (for example,to sum or average all the values in a list property),you can improve performance by providing methods that do the looping within your object and return the appropriate value.

11. Compiled vs. Interpreted Applications

(1) By default,applications created in Visual Basic are compiled as interpreted or p-code executables. At run time,the instructions in the executables are translated or interpreted by a run-time dynamic-link library (DLL).

(2) In many cases,compiling to native code can provide substantial gains in speed over the interpreted versions of the same application; however,this is not always the case.

(3) Note that any calls to objects,DLLs or Visual Basic for Applications run-time functions will negate the performance benefits of native code. This is because relatively little time is spent executing code — the majority of time (usually around 90–95%) is spent inside forms,data objects,Windows .dlls,or the Visual Basic for Applications run time,including intrinsic string and variant handling.

(4) In real-world tests,client applications typically spent about 5% of their total execution time executing the p-code. Hence,if native code was instantaneous,using native code for these programs would provide at most a 5% performance improvement.

(5) What native code does is to enable programmers to write snippets of code or computationally intensive algorithms in Basic that were never possible before because of performance issues. Enabling these "snippets" to run much faster can also improve the responsiveness of certain portions of an application,which improves the perceived performance of the overall application.

12. Compatibility with Other Microsoft Applications

(1) Compatibility with Visual Basic for Applications

Visual Basic for Applications,contained in Vba6.dll,is the underlying language engine for Visual Basic. This library contains all of the language elements that are shared by Visual Basic for Applications and Visual Basic.

Code written in Visual Basic for Applications is portable to Visual Basic with the following limitations: Visual Basic for Applications code that refers to application-specific elements (such as an Microsoft Excel worksheet) may be ported,provided that they contain a fully qualified reference and provided that the referenced application exists on the target machine.

Elements specific to Visual Basic,such as forms and intrinsic controls,are contained in the type library Vb6.olb (which is also visible in the Object Browser). In general,code written in Visual Basic is portable to Visual Basic for Applications as long as it doesn’t reference these elements.

(2) Compatibility with Visual Basic Scripting Edition

Visual Basic Scripting edition (VBScript) is designed to be hosted within an Internet browser,such as the Microsoft Internet Explorer or other,third-party browsers. VBScript is a lightweight and extremely fast language engine designed specifically for environments like the Internet,intranets,or the World Wide Web.

VBScript supports a subset of the Visual Basic for Applications language syntax. You can write VBScript code in Visual Basic’s Code Editor,but you can’t run or test the application in the Visual Basic IDE.

Because VBScript is a cross-platform development language,some of the elements of the Visual Basic for Applications language are not included. These include any file input/output functions,intrinsic constants,intrinsic data types,and so forth. When porting code from Visual Basic to VBScript,it’s important to review your code for unsupported elements.

相关文章

Format[$] ( expr [ , fmt ] ) format 返回变体型 format$ 强...
VB6或者ASP 格式化时间为 MM/dd/yyyy 格式,竟然没有好的办...
在项目中添加如下代码:新建窗口来显示异常信息。 Namespace...
转了这一篇文章,原来一直想用C#做k3的插件开发,vb没有C#用...
Sub 分列() ‘以空格为分隔符,连续空格只算1个。对所选...
  窗体代码 1 Private Sub Text1_OLEDragDrop(Data As Dat...