El costo de Trim()

Recientemente he estado ayudando a un cliente a mejorar el desempeño de una aplicación crítica hecha con Delphi, que procesa miles de transacciones por hora. Haciendo algunos cambios al código, me topé con la necesidad de evaluar el costo de hacer Trim() de algunas variables.

En concreto, me topé con unas 50 o 60 construcciones que tenían una estructura como esta:

if Variable <> '' then 
begin 
  VariableA := VariableA + X; 
  VariableV := VariableB + Trim(Variable); 
end;

Dado que de todas maneras había que re-escribir el código, pensé que era una buena oportunidad para aplicar el principio DRY y que a su vez esto permitiría tener una rutina más fácil de leer.

Por tanto, pensé en hacer una rutina genérica que recibiera las variables (el caso real implicaba cambios más profundos, pero para fines didácticos acá asumiremos que la estructura básica se mantendría):

La nueva rutina sería similar a esta:

procedure AsignaValor(Variable, X: string; 
  var VariableA, VariableB: string); 
begin 
  if Variable <> '' then 
  begin 
    VariableA := VariableA + X; 
    //se ha quitado la llamada a trim 
    VariableV := VariableB + Variable; 
  end; 
end;

De esta manera, la vieja rutina luciría así:

  VariableA := ''; 
  VariableB := ''; 
  //Ahora Trim() se llama al llamar a la nueva rutina 
  AsignaValor(Trim(Variable1), X1, VariableA, VariableB); 
  AsignaValor(Trim(Variable2), X2, VariableA, VariableB); 
  AsignaValor(Trim(Variable3), X3, VariableA, VariableB); 
  AsignaValor(Trim(Variable4), X4, VariableA, VariableB); 
  AsignaValor(Trim(Variable5), X5, VariableA, VariableB);

¡Muy bien, hasta ahora! pero (siempre hay un pero), hay dos cambios imporantes que debía considerar.

Primero, el funcionamiento se alteraría, ya que antes, si una variable contenía una cadena de uno o más espacios, sin caracteres, la asignación ocurría de todas maneras, pero al utilizar la nueva rutina no entraría al if. Luego de valorar la situación, resultó que eso no tenía importancia en este caso, por lo que vamos a valorar el segundo tema, y el motivo de esta entrada:

Cuando una cadena ya estaba vacía, lo cual ocurre con bastante frecuencia, en el flujo anterior del programa, la función Trim() no era llamada al hacer la comparación, ni posteriormente. En esta nueva versión, la función Trim() sería llamada para todas las variables. Tomando en cuenta que esto ocurriría unas 60 o 70 veces por transacción, y que el objetivo es mejorar el desempeño, me pregunté qué tanto cuesta llamar a Trim(”), para medir el impacto de este cambio y estar seguro que no afectaría.

Por ello, hice una pequeña prueba, donde llamo a Trim(”) diez millones de veces, lo cuál arrojó el siguiente “pantallazo”:

Costo del Trim

Como puede verse, la llamada a Trim(”), en mi máquina, toma en promedio tan solo 43.8 nano-segundos. Llamarlo 70 veces tendrá un costo de aproximadamente 3 micro-segundos (1 micro-segundo es la milésima parte de un mili-segundo). He elegido hacerlo diez millones de veces, pues esta es más o menos la cantidad de veces que esta rutina se ejecutará cada hora en horas pico, lo cual en total aumentará el tiempo de proceso en mas o menos medio segundo por hora.

Considerando que dentro de los cambios se han introducido mejoras importantes en el desempeño, que Trim() de todas maneras es llamado para las variables que no están vacías y que el hardware del servidor es más robusto que el de mi PC (o debiera serlo), el costo, en esta ocasión ha resultado aceptable.


Edición 25/nov/2011. El código publicado originalmente no era correcto, en realidad se compara una desigualdad y no una igualdad, si no, realmente no tendría sentido. Gracias a Juan por el comentario que me hizo darme cuenta de este error.

3 Respuestas a “El costo de Trim()

  1. Para eliminar el uso de la función Trim() en el primer código, ¿no sería mejor si simplemente quitases esa asignación?
    Al ser de tipo string y estar vacía, creo que no alteraría el resultado.

    if Variable = ” then
    begin
    VariableA := VariableA + X;
    // VariableV := VariableB + Trim(Variable);
    VariableV := VariableB;
    end;

    ¿Qué opinas?

    • Juan, gracias por tu comentario. El código publicado originalmente contenía un error, y me he dado cuenta gracias a tu comentario. Me justifico explico: Al colocar el <>, lo hice escribiendo los símbolos directamente en el editor, pero al ser símbolos utilizados en HTML, en lugar de convertirlos en su equivalente HTML (&lt; &gt;), los eliminó. En la vista previa de la entrada noté que no había símbolo de comparación… y, ¡puse un igual! Garrafal error el mío, pues el código cambió totalmente de sentido. Eran las 2 AM y la verdad no me percaté de eso cuando leí de nuevo la entrada. Ahora, que leí tu comentario, me di cuenta que el código no hacía sentido… y entonces, tuve ocasión de corregirlo (y comprender que había pasado antes).

  2. De nada jachguate😉 Gracias por contestar. Ahora ya está todo claro.

    Saludos!

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s