c# - uso - dictionary string object
Diccionario Concurrent<TKey, TValue> vs Dictionary<TKey, TValue> (5)
Como dice MSDN
ConcurrentDictionary<TKey, TValue>
Class Representa una colección segura de subprocesos de pares clave-valor a los que se puede acceder mediante varios subprocesos simultáneamente.
Pero como sé, las clases System.Collections.Concurrent
están diseñadas para PLINQ.
Tengo el Dictionary<Key,Value>
que mantiene a los clientes en línea en el servidor, y lo hago seguro para los hilos al bloquear el objeto cuando tengo acceso a él.
¿Puedo reemplazar de forma segura Dictionary<TKey,TValue>
por ConcurrentDictionary<TKey,TValue>
en mi caso? ¿El rendimiento aumentará después del reemplazo?
Here en la Parte 5, Joseph Albahari mencionó que está diseñado para la programación paralela.
- Las colecciones concurrentes están sintonizadas para la programación paralela. Las colecciones convencionales las superan en todos los escenarios excepto en los muy concurrentes.
- Una colección segura para subprocesos no garantiza que el código que lo usa será seguro para subprocesos.
- Si enumera una colección concurrente mientras otro hilo la modifica, no se lanza ninguna excepción. En su lugar, obtienes una mezcla de contenido antiguo y nuevo.
- No hay una versión concurrente de la Lista.
- Las clases simultáneas de pila, cola y bolsa se implementan internamente con listas vinculadas. Esto los hace menos eficientes en memoria que las clases de Pila y Cola no concurrentes, pero mejor para el acceso concurrente porque las listas vinculadas son propicias para implementaciones sin bloqueo o con bloqueo bajo. (Esto se debe a que la inserción de un nodo en una lista enlazada requiere la actualización de solo un par de referencias, mientras que la inserción de un elemento en una estructura similar a una lista puede requerir mover miles de elementos existentes).
Aunque no estoy seguro de las dificultades de reemplazo, pero si tiene algún lugar donde necesite acceder a varios elementos en el diccionario en la misma "sesión de bloqueo", entonces deberá modificar su código.
Podría dar un rendimiento mejorado si Microsoft ha dado bloqueos separados para lectura y escritura, ya que las operaciones de lectura no deberían bloquear otras operaciones de lectura.
No es tan simple como reemplazar el Dictionary
con ConcurrentDictionary
, tendrá que adaptar su código, ya que estas clases tienen nuevos métodos que se comportan de manera diferente, para garantizar la seguridad de subprocesos.
Por ejemplo, en lugar de llamar a Add
o Remove
, tiene TryAdd
y TryRemove
. Es importante que utilice estos métodos que se comportan de forma atómica, ya que si realiza dos llamadas en las que la segunda depende del resultado de la primera, aún tendrá condiciones de carrera y necesitará un lock
.
Puede reemplazar Dictionary<TKey, TValue>
con ConcurrentDictionary<TKey, TValue>
.
Sin embargo, el efecto en el rendimiento puede no ser lo que desea (si hay mucho bloqueo / sincronización, el rendimiento puede sufrir ... pero al menos su colección es segura para subprocesos).
Sí, puede reemplazarlo de manera segura, sin embargo el diccionario diseñado para plinq puede tener algún código adicional para la funcionalidad adicional que no puede usar. Pero la sobrecarga de rendimiento será marginalmente muy pequeña.
Sin saber más sobre lo que estás haciendo dentro de la cerradura, es imposible decirlo.
Por ejemplo, si todos los accesos a tu diccionario se ven así:
lock(lockObject)
{
foo = dict[key];
}
... // elsewhere
lock(lockObject)
{
dict[key] = foo;
}
Entonces estarás bien si lo cambias (aunque probablemente no veas ninguna diferencia en el rendimiento, así que si no está roto, no lo arregles). Sin embargo, si está haciendo algo sofisticado dentro del bloque de bloqueo en el que interactúa con el diccionario, deberá asegurarse de que el diccionario proporcione una única función que pueda lograr lo que está haciendo dentro del bloque de bloqueo. Terminarás con un código que es funcionalmente diferente de lo que tenías antes. Lo más importante que se debe recordar es que el diccionario solo garantiza que las llamadas simultáneas al diccionario se ejecuten de manera serial; no puede manejar casos en los que tiene una sola acción en su código que interactúa con el diccionario varias veces. Casos como ese, cuando no son explicados por el ConcurrentDictionary
, requieren su propio control de concurrencia.
Afortunadamente, el ConcurrentDictionary
proporciona algunas funciones de ayuda para operaciones de varios pasos más comunes como AddOrUpdate
o GetOrAdd
, pero no pueden cubrir todas las circunstancias. Si tiene que trabajar para adaptar su lógica a estas funciones, puede ser mejor manejar su propia concurrencia.