¿Usar try/catch es malo para el rendimiento? Spoiler: no, siempre que nada falle - Code Variables
Code Variables Code Variables

Latest news

جاري التحميل ...

¿Usar try/catch es malo para el rendimiento? Spoiler: no, siempre que nada falle

.NET Core Alguna vez he escuchado, a modo de leyenda urbana, que no era bueno utilizar try/catch porque el mero hecho de usar este tipo de bloque de código afectaba al rendimiento.

La verdad es que de forma intuitiva se puede adivinar que esto no debería ser así. Si no se producen excepciones en un código que tengamos envuelto en un try/catch se debería ejecutar virtualmente a la misma velocidad que si no usáramos este tipo de bloque. Cosa distinta es si producen excepciones: ahí el rendimiento sí se verá seriamente penalizado, pero no es culpa del try/catch sino del propio sistema de gestión de excepciones de .NET.

Pero claro, lo dicho anteriormente es sólo cierto si somos capaces de demostrarlo, así que usaremos nuestro viejo conocido BenchmarkDotnet para desmontar este mito.

El método científico

Para demostrar nuestra afirmación, creamos una aplicación de consola .NET Core en la que añadimos la referencia al paquete NuGet BenchmarkDotNet e introducimos el siguiente código:
[MemoryDiagnoser]
public class Program
{
static void Main(string[] args)
{
BenchmarkRunner.Run<Program>();
Console.ReadLine();
}

[Benchmark]
public int ConvertWithNoTryCatch()
{
return Convert.ToInt32("1");
}

[Benchmark]
public int ConvertWithTryCatch()
{
try
{
return Convert.ToInt32("1");
}
catch (Exception)
{
return 0;
}
}
}
Como se puede ver en el código anterior, los métodos ConvertWithTryCatch() y ConvertWithoutTryCatch() realizan la simple conversión a enero de una cadena de caracteres (ya, sé que existe int.TryParse(), pero entonces no se generarían excepciones ;)). El resultado de ejecutar el test anterior es el siguiente:

| Method | Mean | Error | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated |
|---------------------- |---------:|---------:|---------:|------:|------:|------:|----------:|
| ConvertWithNoTryCatch | 11.33 ns | 0.029 ns | 0.027 ns | - | - | - | - |
| ConvertWithTryCatch | 11.71 ns | 0.251 ns | 0.299 ns | - | - | - | - |
La pequeña diferencia, del orden de nanosegundos es puntual; si efectuamos la medición de nuevo, ambas implementaciones irán variando ligeramente sus tiempos, pero siempre alrededor de esos valores. Por tanto, atendiendo a estos datos podemos concluir que el uso de try/catch no afecta al rendimiento si no se producen excepciones.

¿Pero es esto una optimización de .NET Core, o es igual en .NET Framework? Pues para saberlo, ejecutamos la misma prueba con .NET Framework, y los resultados que obtenemos en esta ocasión son los siguientes:

| Method | Mean | Error | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated |
|---------------------- |---------:|---------:|---------:|------:|------:|------:|----------:|
| ConvertWithNoTryCatch | 52.78 ns | 0.416 ns | 0.368 ns | - | - | - | - |
| ConvertWithTryCatch | 52.42 ns | 0.295 ns | 0.276 ns | - | - | - | - |
Aunque con una importante diferencia de velocidad entre .NET Core y .NET Framework a favor del primero, en ambos casos se puede observar que try/catch sigue sin afectar al rendimiento cuando todo va bien.

Por tanto, mito desmontado ;) Podemos utilizar tranquilamente try/catch si tenemos algo que aportar al tratamiento de una excepción sin que esto afecte al rendimiento.

Aquí podríamos terminar este post, pero seguro que nos quedaríamos con la siguiente pregunta en el tintero...

¿Y qué pasa si salta una excepción?

Ah, amigos, aquí es cuando el panorama cambia totalmente. Todos sabemos que el lanzamiento de una excepción y la parafernalia que ello conlleva supone un auténtico “hachazo” al rendimiento de nuestras aplicaciones, pero llevémoslo a números.

El siguiente test obtiene el tiempo de ejecución del mismo método cuando todo va bien (ConversionOk()) y cuando se producen excepciones (ConversionError()):
[Benchmark]
public int ConversionOk()
{
return ConvertWithTryCatch("1");
}

[Benchmark]
public int ConversionError()
{
return ConvertWithTryCatch("hola");
}

private int ConvertWithTryCatch(string value)
{
try
{
return Convert.ToInt32(value);
}
catch (Exception)
{
return 0;
}
}
Y ojo al resultado, que indica que cuando se produce la excepción, en un escenario simple como el que estamos planteando en la prueba, el tiempo de ejecución es mil veces superior:
|          Method |         Mean |     Error |    StdDev |  Gen 0 | Gen 1 | Gen 2 | Allocated |
|---------------- |-------------:|----------:|----------:|-------:|------:|------:|----------:|
| ConversionOk | 13.42 ns | 0.076 ns | 0.071 ns | - | - | - | - |
| ConversionError | 13,895.49 ns | 43.435 ns | 40.629 ns | 0.0610 | - | - | 536 B |
Obviamente, esta es una de las razones por las que no es recomendable utilizar excepciones para gestionar el flujo normal de nuestras aplicaciones, y suele hacerse sólo para implementar el tratamiento de casos realmente excepcionales.

Publicado en Variable not found.

Comments



All Copyrights Reserved

Code Variables

2019