valor objetos new modificar llenar iterar ejemplos diccionario c# performance dictionary

c# - objetos - ¿Por qué es más rápido verificar si el diccionario contiene la clave, en lugar de detectar la excepción en caso de que no la contenga?



modificar valor diccionario c# (2)

Los diccionarios están diseñados específicamente para hacer búsquedas de llaves súper rápidas. Se implementan como tablas hash y cuanto más entradas, más rápidas son en relación con otros métodos. Se supone que el uso del motor de excepciones solo debe hacerse cuando su método no ha hecho lo que usted diseñó, ya que es un gran conjunto de objetos que le brinda mucha funcionalidad para manejar los errores. ¡Una vez construí una clase de biblioteca completa con todo rodeado de bloques try try y me horroricé al ver la salida de depuración que contenía una línea separada para cada una de las más de 600 excepciones!

Imagina el código:

public class obj { // elided } public static Dictionary<string, obj> dict = new Dictionary<string, obj>();

Método 1

public static obj FromDict1(string name) { if (dict.ContainsKey(name)) { return dict[name]; } return null; }

Método 2

public static obj FromDict2(string name) { try { return dict[name]; } catch (KeyNotFoundException) { return null; } }

Tenía curiosidad por ver si hay una diferencia en el rendimiento de estas 2 funciones, porque la primera DEBERÍA ser MÁS LIGERA que la segunda, dado que debe verificar dos veces si el diccionario contiene un valor, mientras que la segunda función solo necesita acceder al diccionario. una vez pero WOW, en realidad es lo opuesto:

Bucle para valores 1 000 000 (con 100 000 existentes y 900 000 no existentes):

Primera función: 306 milisegundos.

Segunda función: 20483 milisegundos.

¿Porqué es eso?

EDITAR: Como puede observar en los comentarios que se encuentran debajo de esta pregunta, el rendimiento de la segunda función es ligeramente mejor que la primera en caso de que haya 0 claves no existentes. Pero una vez que hay al menos 1 o más claves no existentes, el rendimiento de la segunda disminuye rápidamente.


Por un lado, lanzar excepciones es inherentemente costoso , porque la pila tiene que desenrollarse, etc.
Por otro lado, acceder a un valor en un diccionario por su clave es barato, porque es una operación rápida, O (1).

Por cierto: la forma correcta de hacer esto es usar TryGetValue

obj item; if(!dict.TryGetValue(name, out item)) return null; return item;

Esto accede al diccionario solo una vez en lugar de dos veces.
Si realmente desea simplemente devolver null si la clave no existe, el código anterior se puede simplificar aún más:

obj item; dict.TryGetValue(name, out item); return item;

Esto funciona, porque TryGetValue establece el item en null si no existe una clave con name .