2011-03-14 11 views
25

Como MSDN saysConcurrentDictionary <TKey,TValue> vs Diccionario <TKey,TValue>

ConcurrentDictionary<TKey, TValue> clase representa una colección thread-safe de pares de valores clave que se puede acceder por múltiples hilos simultáneamente.

Pero como sé, las clases System.Collections.Concurrent están diseñadas para PLINQ.

Tengo Dictionary<Key,Value> que mantiene clientes en línea en el servidor, y lo hago seguro mediante el bloqueo de objeto cuando tengo acceso a él.

¿Puedo reemplazar con seguridad Dictionary<TKey,TValue> por ConcurrentDictionary<TKey,TValue> en mi caso? ¿aumentará el rendimiento después del reemplazo?

Here en la parte 5 José Albahari indican que diseñó para la programación paralela

  • Las colecciones concurrentes están sintonizados para la programación paralela. Las colecciones convencionales las superan en todos los escenarios, excepto en los altamente concurrentes.
  • Una recopilación segura de subprocesos no garantiza que el código que la utilice sea seguro para subprocesos.
  • Si enumera sobre una colección concurrente mientras otro hilo la modifica, no se lanza ninguna excepción. En cambio, obtienes una mezcla de contenido antiguo y nuevo.
  • No hay una versión concurrente de List.
  • Las clases concurrentes de pila, cola y bolsa se implementan internamente con listas vinculadas. Esto los hace menos eficientes en la memoria que las clases de Stack y Queue no concurrentes, pero es mejor para el acceso simultáneo porque las listas enlazadas son propicias para implementaciones sin bloqueo o bajo bloqueo. (Esto se debe a la inserción de un nodo en una lista enlazada es necesario actualizar sólo un par de referencias, mientras que la inserción de un elemento en una estructura de lista similar puede requerir que se mueven miles de elementos existentes.)
+0

No estoy al tanto del hecho de que las clases de System.Collections.Concurrent están "diseñadas para PLINQ", ¿de dónde sacas esa idea? – BrokenGlass

+0

@BrokenGlass: Tal vez en el sentido de que los tipos de lambda y anónimos están "diseñados para LINQ"; llegaron a estar en el marco * debido a * LINQ, pero definitivamente tienen aplicabilidad más allá. –

+0

@BrokenGlass y @Adam Robinson, consulte la publicación editada –

Respuesta

16

Sin saber más acerca de lo que está haciendo dentro de la cerradura, entonces es imposible decirlo.

Por ejemplo, si la totalidad de su acceso diccionario tiene el siguiente aspecto:

lock(lockObject) 
{ 
    foo = dict[key]; 
} 

... // elsewhere 

lock(lockObject) 
{ 
    dict[key] = foo; 
} 

A continuación, se le multa de ponerlo a cabo (aunque es probable que no verá ninguna diferencia en el rendimiento, por lo que si ain no se rompió, no lo arregles).Sin embargo, si está haciendo algo sofisticado dentro del bloque de bloqueo donde interactúa con el diccionario, entonces deberá asegurarse de que el diccionario proporcione una función única que puede lograr lo que está haciendo dentro del bloque de bloqueo. de lo contrario, terminará con un código que es funcionalmente diferente de lo que tenía antes. Lo más importante que hay que recordar es que el diccionario solo garantiza que las llamadas concurrentes al diccionario se ejecuten en serie; no puede manejar casos donde tiene una sola acción en su código que interactúa con el diccionario varias veces. Casos como ese, cuando no se contabilizan en el ConcurrentDictionary, requieren su propio control de concurrencia.

Afortunadamente, el ConcurrentDictionary proporciona algunas funciones de ayuda para las operaciones más comunes de varios pasos como AddOrUpdate o GetOrAdd, pero no pueden cubrir todas las circunstancias. Si tiene que trabajar para calzar su lógica en estas funciones, puede ser mejor manejar su propia concurrencia.

1

Puede reemplazar Dictionary<TKey, TValue> con ConcurrentDictionary<TKey, TValue> .

Sin embargo, el efecto en el rendimiento puede no ser el deseado (si hay un montón de bloqueo/sincronización, el rendimiento puede sufrir ... pero al menos su colección es segura para subprocesos).

1

Si bien no estoy seguro acerca de las dificultades de reemplazo, pero si tiene un lugar donde necesita acceder a varios elementos en el diccionario en la misma "sesión de bloqueo", tendrá que modificar su código.

Podría proporcionar un mejor rendimiento si Microsoft ha otorgado cerraduras separadas para lectura y escritura, ya que las operaciones de lectura no deberían bloquear otras operaciones de lectura.

0

Sí, puede reemplazar de forma segura, sin embargo, el diccionario diseñado para plinq puede tener algún código adicional para funciones adicionales que no puede usar. Pero la sobrecarga del rendimiento será marginalmente muy pequeña.

3

No es tan simple como reemplazar Dictionary con ConcurrentDictionary, tendrá que adaptar su código, ya que estas clases tienen métodos nuevos que se comportan de manera diferente, para garantizar la seguridad del hilo.

Ej., En lugar de llamar o AddRemove, que tienen TryAdd y TryRemove. Es importante que uses estos métodos que se comportan atómicamente, como si hicieras dos llamadas donde la segunda depende del resultado de la primera, todavía tendrás condiciones de carrera y necesitas un lock.

Cuestiones relacionadas