Optimizar el código
A menos que desarrolle tareas como la generación de fractales, sus
aplicaciones raramente se verán limitadas por la velocidad de ejecución del
código. Normalmente son otros factores, como la velocidad de vídeo, los retrasos
de la red o la actividad del disco, los que limitan las aplicaciones. Por
ejemplo, cuando un formulario tarda en cargarse, puede deberse al número de
controles y gráficos del formulario más que a la lentitud del código del evento
Form_Load. Sin embargo, puede encontrar puntos del programa en los que la
velocidad del código es el factor principal, especialmente en las rutinas a las
que se llama con mucha frecuencia. Cuando éste sea el caso, puede usar varias
técnicas para incrementar la velocidad real de las aplicaciones:
- Evitar el uso de variables Variant.
- Usar variables Long Integer y aritmética de números
enteros. - Pasar a variables las propiedades utilizadas con mayor frecuencia.
- Usar variables de nivel de módulo en lugar de variables estáticas.
- Reemplazar las llamadas a procedimientos por código en línea.
- Usar constantes siempre que sea posible.
- Pasar argumentos con ByVal en lugar de ByRef.
- Usar argumentos opcionales con tipo.
- Usar colecciones.
Incluso si no va a optimizar la velocidad del código, conviene tener
presentes estas técnicas y los principios en los que se basan. Si adquiere el
hábito de elegir algoritmos más eficientes al escribir código, obtendrá una
ventaja adicional a la velocidad de la aplicación.
Evitar el uso de variables VariantEl tipo de datos predeterminado de Visual Basic es
Variant. Es cómodo
para los programadores principiantes y en aplicaciones en las que la velocidad
de procesamiento no es importante. Sin embargo, si piensa optimizar la velocidad
real de su aplicación, debe evitar el uso de variables
Variant. Como
Visual Basic convierte las variables
Variant al tipo de datos apropiado
en tiempo de ejecución, las operaciones con otros tipos de datos simples
eliminan este paso adicional y son más rápidas que sus equivalentes
Variant.
Un buen sistema para no usar variables
Variant es usar la instrucción
Option Explicit, que le obliga a declarar todas las variables. Para usar
Option Explicit, active la casilla de verificación
Requerir
declaración de variables en la ficha
Editor del cuadro de diálogo
Opciones, disponible en el menú
Herramientas.
Tenga cuidado cuando declara múltiples variables: si no utiliza la cláusula
As
tipo, se considerarán variables
Variant. Por ejemplo, en la
siguiente declaración, X e Y son Variant:
Escritas de esta manera, las tres variables son de tipo
Long:
Dim X As Long, Y As Long, Z As Long
Para obtener más información Para aprender más
acerca de los tipos de datos de Visual Basic, vea "Tipos de datos" en
"Fundamentos de programación".
Uso de variables Long Integer y aritmética de números enterosEn las operaciones aritméticas, evite las variables
Currency,
Single y
Double. Utilice variables
Long Integer siempre que
pueda, especialmente dentro de los bucles.
Long Integer es el tipo de
datos nativo de las CPU de 32 bits, de forma que las operaciones efectuadas
sobre ellos son muy rápidas; si no puede usar la variable
Long, la opción
más parecida son los tipos de datos
Integer o
Byte. En muchos
casos, puede usar el tipo
Long Integer cuando se requiere un valor con
punto flotante. Por ejemplo, si establece la propiedad
ScaleMode de todos
los formularios y controles de imágenes a twips o píxeles, puede usar el tipo
Long Integer en todos los valores de tamaño y posición de los controles y
los métodos gráficos.
Cuando realice divisiones, utilice el operador de división de enteros (\) si
no necesita un resultado decimal. La aritmética de números enteros siempre es
más rápida que la aritmética de punto flotante, ya que no hay que trasladar la
operación a un coprocesador matemático. Si necesita calcular valores decimales,
el tipo de datos
Double es más rápido que el tipo de datos
Currency.
En la tabla siguiente los tipos de datos numéricos están clasificados según
su velocidad.
Tipo de datos numérico | Velocidad |
Long | Máxima |
Integer | |
Byte | |
Single | |
Double | |
Currency | Mínima |
Almacenamiento en caché de las propiedades utilizadas con mayor frecuencia
en variablesLos valores de las variables se obtienen y se establecen con más rapidez que
los de las propiedades. Si va a leer frecuentemente el valor de una propiedad
(como en un bucle), su código se ejecutará más deprisa si asigna la propiedad a
una variable externa al bucle y después utiliza la variable en lugar de la
propiedad. Las variables suelen ser entre 10 y 20 veces más rápidas que las
propiedades del mismo tipo.
No lea nunca el valor de una propiedad más de una vez dentro de un
procedimiento, a menos que sepa que el valor ha cambiado. En su lugar, asigne el
valor de la propiedad a una variable y utilice la variable en el resto del
código. Por ejemplo, este código es muy lento:
For i = 0 To 10
picIcon(i).Left = picPallete.Left
Next I
Escrito de esta manera, es mucho más rápido:
picLeft = picPallete.Left
For i = 0 To 10
picIcon(i).Left = picLeft
Next I
De igual manera, este código . . .
Do Until EOF(F)
Line Input #F, nextLine
Text1.Text = Text1.Text + nextLine
Loop
. . . es mucho más lento que éste:
Do Until EOF(F)
Line Input #F, nextLine
bufferVar = bufferVar & nextLine & vbCrLf
Loop
Text1.Text = bufferVar
Sin embargo, este código hace el mismo trabajo y es aún más rápido:
Text1.Text = Input(F, EOF(F))
Como puede ver, hay varios métodos para conseguir el mismo objetivo; el mejor
algoritmo también es la mejor optimización.
La misma técnica puede aplicarse a los valores devueltos por las funciones.
Almacenar estos valores en memoria caché evita la repetición de las llamadas a
la biblioteca de vínculos dinámicos (DLL) de tiempo de ejecución,
Msvbvm60.dll.
Usar variables de nivel de módulo en lugar de variables estáticasAunque las variables declaradas con el modificador Static son útiles para
almacenar un valor a través de ejecuciones múltiples de un procedimiento, son
más lentas que las variables locales. Si almacena el mismo valor en una variable
de nivel de módulo, su procedimiento se ejecutará más rápidamente. Observe sin
embargo que deberá asegurarse de que un procedimiento tan sólo tiene la
posibilidad de modificar la variable a nivel de módulo. La contrapartida aquí es
que su código será menos legible y más difícil de mantener.
Reemplazar llamadas a procedimientos por código en líneaAunque el uso de procedimientos hace que el código sea más modular, las
llamadas a los procedimientos siempre conllevan algo de proceso y de tiempo
adicionales. Si tiene un bucle que llama muchas veces a un procedimiento, puede
eliminar esta carga si quita la llamada al procedimiento y coloca el cuerpo del
procedimiento directamente dentro del bucle. Sin embargo, si coloca la misma
línea de código en varios bucles, el código duplicado aumenta el tamaño de la
aplicación. También aumenta las posibilidades de olvidarse de actualizar todas
las secciones repetidas cuando las modifique.
Del mismo modo, la llamada a un procedimiento ubicado dentro del propio
módulo es más rápida que una llamada al mismo módulo hecha desde un módulo .BAS
separado; si es necesario llamar al mismo procedimiento desde módulos múltiples,
dicha mejora quedará anulada.
Uso de constantes siempre que sea posibleEl empleo de constantes hace que la aplicación sea más rápida. Las constantes
también hacen que el código sea más legible y fácil de mantener. Si hay en el
código cadenas o números que no cambian, declárelos como constantes. Las
constantes se resuelven al compilar el programa, y el valor apropiado se escribe
en el código. Sin embargo, si emplea variables, cada vez que la aplicación
ejecuta y encuentra una variable, tiene que leer el valor actual de la
variable.
Siempre que sea posible, utilice las constantes intrínsecas del Examinador de
objetos en vez de crear las suyas propias. No tiene que preocuparse por incluir
módulos que contengan constantes que no se utilizan en la aplicación; cuando se
genera el archivo .exe, se quitan las constantes que no se utilizan.
Paso de argumentos no modificados con ByVal en lugar de ByRefCuando escriba procedimientos
Sub o
Function que incluyan
argumentos no modificados, es más rápido pasar los argumentos por valor
(
ByVal) que por referencia (
ByRef). En Visual Basic los argumentos
se pasan
ByRef de forma predeterminada, pero muy pocos procedimientos
modifican los valores de sus argumentos. Si no necesita modificar los argumentos
dentro del procedimiento, defínalos
ByVal, como en el ejemplo
siguiente:
Private Sub DoSomething(ByVal strName As String, _
ByVal intAge As Integer)
Usar argumentos opcionales con tipoLos argumentos opcionales con tipo pueden aumentar la velocidad de las
llamadas a procedimientos y funciones. En las versiones anteriores de Visual
Basic, los argumentos opcionales tenían que ser de tipo
Variant. Si el
procedimiento tenía argumentos
ByVal, como en el ejemplo siguiente, los
16 bytes de la variable
Variant tenían que pasar a la pila.
Private Sub DoSomething(ByVal strName As String, _
Optional ByVal vntAge As Variant, _
Optional ByVal vntWeight As Variant)
La función utiliza menos espacio de pila en cada llamada y mueve menos datos
en la memoria si utiliza argumentos opcionales con tipo:
Private Sub DoSomething(ByVal strName As String, _
Optional ByVal intAge As Integer, _
Optional ByVal intWeight As Integer)
Los argumentos opcionales con tipo tienen un acceso más rápido que las
variables
Variant y por añadidura recibirá un mensaje de error en tiempo
de compilación si pasa datos que no sean del tipo declarado.
Uso de coleccionesLa posibilidad de definir y usar colecciones de objetos es una característica
muy eficaz de Visual Basic. Si bien las colecciones pueden ser muy útiles, debe
usarlas correctamente para obtener el mayor rendimiento:
- Utilice For Each...Next en lugar de For...Next.
- Evite usar los argumentos Before y After cuando agregue
objetos a una colección. - Utilice colecciones con claves en vez de matrices para los grupos de
objetos de un mismo tipo.
Las colecciones le permiten iterar por ellas mediante un bucle
For...Next. Sin embargo, la construcción
For Each...Next es más
legible y en muchos casos más rápida. El creador de la colección implementa la
iteración
For Each...Next, de modo que la velocidad real variará entre un
objeto de colección y otro. Sin embargo,
For Each...Next raramente será
más lento que
For...Next, puesto que la implementación más simple es una
iteración lineal del estilo
For...Next. En algunos casos, el
implementador puede usar una implementación más sofisticada que la iteración
lineal y, por tanto,
For Each...Next puede ser mucho más rápido.
Es más rápido agregar objetos a una colección si no utiliza los argumentos
Before y
After. Estos argumentos requieren que Visual Basic busque
otro objeto de la colección antes de agregar el nuevo.
Cuando tiene un grupo de objetos de un mismo tipo, puede administrarlos
dentro de una colección o de una matriz (si son de distintos tipos, la colección
es la única opción posible). Desde el punto de vista de la velocidad, la
elección depende de cómo piensa tener acceso a los objetos. Si puede asociar una
clave única a cada objeto, la colección es la opción más rápida. Usar una clave
para obtener un objeto de una colección es más rápido que recorrer una matriz de
forma secuencial. Sin embargo, si no tiene dichas claves y, por tanto, tiene que
recorrer siempre todos los objetos, la matriz es la mejor opción. Las matrices
se recorren secuencialmente con más rapidez que las colecciones.
Para números reducidos de objetos, las matrices utilizan menos memoria y
suelen tener un acceso más rápido. El número de objetos a partir del cual las
colecciones son más eficientes que las matrices es aproximadamente 100; sin
embargo, esto puede variar dependiendo de la velocidad del procesador y la
memoria disponible.