2010-04-18 15 views
64

Estoy leyendo el libro Java Concurrency in Practice. En el capítulo 15, están hablando de los algoritmos no bloqueantes y el método compare-and-swap (CAS).Concurrencia de Java: CAS vs Locking

Está escrito que CAS funciona mucho mejor que los métodos de bloqueo. Quiero preguntarle a las personas que ya trabajaron con estos dos conceptos y me gustaría saber cuándo está prefiriendo cuál de estos conceptos? ¿Es realmente mucho más rápido?

Para mí, el uso de cerraduras es mucho más claro y más fácil de entender y tal vez incluso mejor para mantener (por favor, corríjanme si me equivoco). ¿Deberíamos centrarnos realmente en crear nuestro código simultáneo relacionado con CAS que bloqueos para obtener un mejor impulso de rendimiento o la sostenibilidad es más importante?

Sé que tal vez no haya una regla estricta sobre cuándo usar qué. Pero me gustaría escuchar algunas opiniones, experiencias con el nuevo concepto de CAS.

Respuesta

37

CAS es generalmente mucho más rápido que el bloqueo, pero depende del grado de contención. Debido a que CAS puede forzar un reintento si el valor cambia entre leer y comparar, un hilo teóricamente puede atascarse en una espera ocupada si la variable en cuestión está siendo golpeada duramente por muchos otros hilos (o si es costoso calcular un nuevo valor) del valor anterior (o ambos)).

El problema principal con CAS es que es mucho más difícil programar con el bloqueo correctamente. Tenga en cuenta que el bloqueo es, a su vez, mucho más difícil de usar correctamente que el envío de mensajes o STM, por lo que no debe tomar esto como un respaldo para el uso de bloqueos.

+0

Acepto, poniendo énfasis en * el gasto de calcular un nuevo valor *. A menudo es tan grande que hace que la estrategia sin bloqueo pierda a la basada en bloqueo. –

16

Puede ver los números entre una ConcurrentLinkedQueue y una BlockingQueue. Lo que verá es que CAS es notablemente más rápido en aplicaciones moderadas (más realistas en aplicaciones del mundo real).

La propiedad más atractiva de los algoritmos no bloqueantes es el hecho de que si falla un hilo (falta de caché, o peor, falla de seg), otros subprocesos no notarán este error y pueden continuar. Sin embargo, cuando se adquiere un bloqueo, si el hilo que contiene el bloqueo tiene algún tipo de falla del sistema operativo, cada hebra que espere a que se libere el bloqueo también será golpeada con el fallo.

Para responder a sus preguntas, sí algoritmos o colecciones seguros para subprocesos no bloqueantes (ConcurrentLinkedQueue, ConcurrentSkipListMap/Set) pueden ser significativamente más rápidos que sus contrapartes de bloqueo. Sin embargo, como señaló Marcelo, corregir los algoritmos que no bloquean es muy difícil y requiere mucha consideración.

Deberías leer sobre el Michael and Scott Queue, esta es la implementación de colas para ConcurrentLinkedQueue y explica cómo manejar una función atómica bidireccional segura para hilos con un solo CAS.

+1

El artículo sobre "Michael y Scott Queue" es interesante. ¡Gracias! – Prine

12

Hay buen libro fuertemente relacionada con el tema de la concurrencia libre de bloqueo: "El arte de la programación multi-procesador" de Maurice Herlihy

+0

También su presentación [parte 1] (http://research.microsoft.com/apps/video/default.aspx?id=168298) y [parte 2] (http://research.microsoft.com/apps/video /default.aspx?id=169831) valen la pena. –

23

La velocidad relativa de las operaciones es en gran medida no sea un problema. Lo que es relevante es la diferencia en la escalabilidad entre algoritmos basados ​​en bloqueo y no bloqueo. Y si está ejecutando un sistema central de 1 o 2, deje de pensar en esas cosas.

Los algoritmos sin bloqueo generalmente escalan mejor porque tienen "secciones críticas" más cortas que los algoritmos basados ​​en bloqueo.

5

Si busca una comparación del mundo real, aquí tiene una. Nuestra aplicación tiene dos (2) subprocesos 1) Un hilo de lectura para la captura de paquetes de red y 2) un hilo de consumidor que toma el paquete, lo cuenta e informa las estadísticas.

Tema # 1 bolsas de un solo paquete a la vez con hilo # 2

Resultado # 1 - utiliza una conversión basado CAS personalizado utilizando los mismos principios que SynchronousQueue, donde nuestra clase se llama CASSynchronousQueue:

30,766,538 packets in 59.999 seconds :: 500.763Kpps, 1.115Gbps 0 drops 
libpcap statistics: recv=61,251,128, drop=0(0.0%), ifdrop=0 

Resultado # 2 - cuando reemplazamos nuestra implementación de la EAP con el estándar de java S ynchronousQueue:

8,782,647 packets in 59.999 seconds :: 142.950Kpps, 324.957Mbps 0 drops 
libpcap statistics: recv=69,955,666, drop=52,369,516(74.9%), ifdrop=0 

no creo que la diferencia de rendimiento no podría ser más clara.

Cuestiones relacionadas