2009-02-13 21 views
33

he estado tratando de optimizar mi código para hacerlo un poco más conciso y legible y esperaba que no causara un peor rendimiento al hacerlo. Creo que mis cambios pueden haber ralentizado mi aplicación, pero podría ser solo en mi cabeza. ¿Hay alguna diferencia de rendimiento entre:?: Operador vs. Si Statement Performance

Command.Parameters["@EMAIL"].Value = email ?? String.Empty; 

y

Command.Parameters["@EMAIL"].Value = (email == null) ? String.Empty: email; 

y

if (email == null) 
{ 
    Command.Parameters["@EMAIL"].Value = String.Empty 
} 
else 
{ 
    Command.Parameters["@EMAIL"].Value = email 
} 

Mi preferencia para facilitar la lectura sería el operador coalescente nula, simplemente no quería que afecte actuación.

Respuesta

68

en mi humilde opinión, optimizar para facilitar la lectura y comprensión - cualquier beneficio de rendimiento en tiempo de ejecución probablemente será mínimo en comparación con el tiempo que le lleva en el mundo real cuando vuelvas a este código en un par de meses y tratar de entender lo diablos que estabas haciendo en primer lugar.

+13

Por supuesto, tenga en cuenta que muchos programadores pueden leer? : declaraciones tan rápido como las declaraciones regulares de if. En algunos casos, son incluso más claros que el uso de sentencias if/else sin llaves. – NotMe

+1

Estoy de acuerdo. Muchas publicaciones aquí son preguntas de rendimiento, preguntando por ajustes menores (¿es ++ más rápido que + = 1?) Que realmente no importan. La velocidad proviene de la complejidad algorítmica: se reducen las copias de memoria masivas, se buscan contenedores rápidamente, se procesa de forma adecuada. Los ajustes menores no tienen impacto en el rendimiento. – abelenky

+9

-1: Mientras que los puntos de chublogga son todos verdaderos y válidos y bien expresado, que no responden a la pregunta original. El OP es un adulto que puede hacer sus propias elecciones de arquitectura/legibilidad, y la respuesta de casperOne es realmente una respuesta más interesante y directa a la cuestión específica del rendimiento. – nezroy

6

Sospecho que no habrá ninguna diferencia de rendimiento.

Al lado de eso, me pregunto por qué tiene alguna preocupación de favorecer una declaración sobre la otra en este caso? Quiero decir: el impacto en el rendimiento (si hubiera alguno) sería mínimo. En mi humilde opinión, esto sería una especie de micro-optimización, y no debería valer la pena el esfuerzo.
Elegiría la declaración que sea más legible, más clara y no se preocupe por el rendimiento, ya que sería de influencia mínima (en este caso).

+0

La forma en que fue escrito originalmente era un montón de declaraciones si y cuando lo cambié, parecía que el programa tuvo un pequeño impacto en el rendimiento. Tal vez fue un incidente aislado pero despertó mi interés más que nada. – Jon

6

Casi ninguna diferencia de rendimiento significativa en este caso.

Cuando la diferencia de rendimiento es insignificante, se trata de código legible.

+1

Lo refinaría para decir "En los casos donde no hay una diferencia de rendimiento significativa, todo se trata de código legible". A veces, hay una diferencia de rendimiento, y a veces esa diferencia es significativa, en cuyo caso, la legibilidad del código puede quedar relegada. – phoog

+1

¿Cómo es eso diferente de lo que dije? –

+0

@ chris-ballance La diferencia está obviamente en donde uno pone el énfasis. –

71

Usted está tratando de micro-optimize aquí, y eso es generalmente un gran no-no. A menos que tenga análisis de desempeño que le muestren que esto es un problema, ni siquiera vale la pena cambiarlo.

Para uso general, la respuesta correcta es la que sea más fácil de mantener.

Por el placer de hacerlo, sin embargo, la IL para el operador coalescente nula es:

L_0001: ldsfld string ConsoleApplication2.Program::myString 
L_0006: dup 
L_0007: brtrue.s L_000f 
L_0009: pop 
L_000a: ldsfld string [mscorlib]System.String::Empty 
L_000f: stloc.0 

Y la IL para el interruptor es:

L_0001: ldsfld string ConsoleApplication2.Program::myString 
L_0006: brfalse.s L_000f 
L_0008: ldsfld string ConsoleApplication2.Program::myString 
L_000d: br.s L_0014 
L_000f: ldsfld string [mscorlib]System.String::Empty 
L_0014: stloc.0 

Para el null coalescing operator, si el valor es null, luego se ejecutan seis de las instrucciones, mientras que con el switch, se realizan cuatro operaciones.

En el caso de un valor no null, el operador coalescente nulo realiza cuatro operaciones contra cinco operaciones.

Por supuesto, esto supone que todas las operaciones IL toman la misma cantidad de tiempo, que no es el caso.

De todos modos, con suerte se puede ver cómo la optimización en esta microescala puede comenzar a disminuir los retornos con bastante rapidez.

Dicho esto, al final, para la mayoría de los casos lo que es la más fácil de leer y mantener en este caso es la respuesta correcta.

Si encuentra que está haciendo esto en una escala en la que resulta ineficiente (y esos casos son pocos y distantes), entonces debe medir para ver cuál tiene un mejor rendimiento y luego hacer esa optimización específica.

+0

'L_0006: dup' - Mostrando mi propia ignorancia aquí, pero ¿por qué sería necesario que dup aquí? –

+0

Ohhh, ya veo. Si no es nulo, se almacena a 000f y no aparece. Tiene sentido. –

+0

¿qué pasa con string.IsNullOrEmpty()? –

17

creo que mis cambios podrían haber ralentizado por mi solicitud, pero simplemente podría estar en mi cabeza.

A no ser que en realidad se está midiendo rendimiento, todo está en su cabeza y una especulación ociosa.

(No meterse con usted en particular, pero es tan decepcionante ver una pregunta tras otra acerca de la Micro-optimizaciones (así como muchas de las respuestas) que no contienen la palabra "medida".)

1

es una cuestión de si el código de máquina es eficiente o humanamente legible código. A medida que hacemos que sea más legible para nosotros, hace que la máquina haga Complex interprete el código y viceversa ...

2

Por cuestión de discusión ... if/then/else funciona tan rápido como la operación?: Ternary tan rápido como un cambio de nivel único/declaración de caso.

Here are some performance benchmarks with the C# code.

Es sólo cuando comienza a recibir 2-3 niveles de profundidad en las declaraciones de casos que el rendimiento comienza a ser impactado severamente. Es decir, algo así como este ejemplo ridículo:

switch (x % 3) 
    { 
     case 0: 
      switch (y % 3) 
      { 
       case 0: total += 3; 
        break; 
       case 1: total += 2; 
        break; 
       case 2: total += 1; 
        break; 
       default: total += 0; 
        break; 
      } 
      break; 
     case 1: 
      switch (y % 3) 
      { 
       case 0: total += 3; 
        break; 
       case 1: total += 2; 
        break; 
       case 2: total += 1; 
        break; 
       default: total += 0; 
        break; 
      } 
      break; 
    case 2: 
      switch (y % 3) 
      { 
       case 0: total += 3; 
        break; 
       case 1: total += 2; 
        break; 
       case 2: total += 1; 
        break; 
       default: total += 0; 
        break; 
      } 
      break; 
    default: 
     switch (y % 3) 
     { 
      case 0: total += 3; 
       break; 
      case 1: total += 2; 
       break; 
      case 2: total += 1; 
       break; 
      default: total += 0; 
       break; 
     } 
     break; 
    }