¿Qué es la contención de hilos?

120

¿Alguien puede explicar simplemente qué es la contención de hilos?

Lo he buscado en Google, pero parece que no puedo encontrar una explicación simple.

Tony el león
fuente
9
Por lo tanto, escriba cuál es su pensamiento vago, para que podamos ver dónde puede estar o su comprensión puede ser correcta.
James Black

Respuestas:

87

Básicamente, la contención de subprocesos es una condición en la que un subproceso está esperando un bloqueo / objeto que actualmente está retenido por otro subproceso. Por lo tanto, este subproceso en espera no puede usar ese objeto hasta que el otro subproceso haya desbloqueado ese objeto en particular.

keyboardP
fuente
53
Esta respuesta está incompleta (como la mayoría de las otras). Si bien una cerradura es un tipo de cosa por la que puede haber disputas, está lejos de ser la única. También puede haber disputas por recursos sin candado. (Por ejemplo, si dos subprocesos siguen incrementando atómicamente el mismo número entero, pueden experimentar contención debido al ping-pong de caché. No hay bloqueos involucrados).
David Schwartz
En el caso de un bloqueo de intérprete global (GIL) como en CPython, donde un hilo siempre debe adquirir el GIL, varios hilos que se ejecutan en el mismo proceso están en disputa por defecto.
Acumenus
Creo que lo has explicado en términos de Deadlock, pero es muy diferente del Deadlock.
Harshit Gupta
185

Varias respuestas parecen centrarse en la contención de bloqueos, pero los bloqueos no son los únicos recursos en los que se puede experimentar la contención. La contención es simplemente cuando dos subprocesos intentan acceder al mismo recurso o recursos relacionados de tal manera que al menos uno de los subprocesos contendientes se ejecuta más lentamente de lo que lo haría si los otros subprocesos no se estuvieran ejecutando.

El ejemplo más obvio de contienda está en una cerradura. Si el hilo A tiene un bloqueo y el hilo B quiere adquirir ese mismo bloqueo, el hilo B tendrá que esperar hasta que el hilo A libere el bloqueo.

Ahora, esto es específico de la plataforma, pero el hilo puede experimentar ralentizaciones incluso si nunca tiene que esperar a que el otro hilo libere el bloqueo. Esto se debe a que un bloqueo protege algún tipo de datos y, a menudo, los datos en sí también se contendrán.

Por ejemplo, considere un hilo que adquiere un bloqueo, modifica un objeto, luego libera el bloqueo y hace algunas otras cosas. Si dos subprocesos están haciendo esto, incluso si nunca luchan por el bloqueo, los subprocesos pueden correr mucho más lento de lo que lo harían si solo se estuviera ejecutando un subproceso.

¿Por qué? Supongamos que cada hilo se ejecuta en su propio núcleo en una CPU x86 moderna y los núcleos no comparten una caché L2. Con solo un hilo, el objeto puede permanecer en la caché L2 la mayor parte del tiempo. Con ambos subprocesos en ejecución, cada vez que un subproceso modifica el objeto, el otro subproceso encontrará que los datos no están en su caché L2 porque la otra CPU invalida la línea de caché. En un Pentium D, por ejemplo, esto hará que el código se ejecute a la velocidad FSB, que es mucho menor que la velocidad de la caché L2.

Dado que la contención puede ocurrir incluso si el bloqueo en sí mismo no se disputa, la contención también puede ocurrir cuando no hay bloqueo. Por ejemplo, digamos que su CPU admite un incremento atómico de una variable de 32 bits. Si un hilo sigue aumentando y disminuyendo una variable, la variable estará activa en la caché la mayor parte del tiempo. Si dos subprocesos lo hacen, sus cachés competirán por la propiedad de la memoria que contiene esa variable, y muchos accesos serán más lentos ya que el protocolo de coherencia de caché opera para asegurar la propiedad de cada núcleo de la línea de caché.

Irónicamente, las cerraduras suelen reducir la contención. ¿Por qué? Porque sin un bloqueo, dos subprocesos podrían operar en el mismo objeto o colección y causar mucha contención (por ejemplo, hay colas sin bloqueo). Los bloqueos tenderán a desprogramar los subprocesos rivales, permitiendo que se ejecuten los subprocesos no rivales. Si el subproceso A tiene un bloqueo y el subproceso B quiere ese mismo bloqueo, la implementación puede ejecutar el subproceso C en su lugar. Si el hilo C no necesita ese bloqueo, entonces la contención futura entre los hilos A y B puede evitarse por un tiempo. (Por supuesto, esto supone que hay otros subprocesos que podrían ejecutarse. No ayudará si la única forma en que el sistema en su conjunto puede hacer un progreso útil es ejecutando subprocesos que compiten).

David Schwartz
fuente
4
+1 Además, solo para hacer esto explícito, las dos variables por las que dos núcleos están peleando ni siquiera necesitan ser la misma variable para causar contención, solo tienen que estar almacenadas en la memoria en la misma línea de caché. Acolchar estructuras y / o alinear estructuras con la memoria puede ayudar a evitar esta forma de contención.
Rob_before_edits
1
@David, por favor, ayude a comprender el último párrafo de su respuesta con más detalle
alumno
4
@Naroji Haz una pregunta al respecto.
David Schwartz
@DavidSchwartz, ¿eres programador en C?
Pacerier
@Pacerier C ++ principalmente.
David Schwartz
19

Desde aqui :

Una contención ocurre cuando un hilo está esperando un recurso que no está disponible fácilmente; ralentiza la ejecución de su código, pero puede desaparecer con el tiempo.

Un interbloqueo se produce cuando un subproceso está esperando un recurso que un segundo subproceso ha bloqueado y el segundo subproceso está esperando un recurso que el primer subproceso ha bloqueado. Más de dos subprocesos pueden estar involucrados en un interbloqueo. Un punto muerto nunca se resuelve por sí solo. A menudo hace que se detenga toda la aplicación o la parte que está experimentando el interbloqueo.

Jon B
fuente
Esto también explica la diferencia entre la Contención de subprocesos y el Interbloqueo
Sankalp
3

Creo que debería haber alguna aclaración del OP sobre el trasfondo de la pregunta; puedo pensar en 2 respuestas (aunque estoy seguro de que hay adiciones a esta lista):

  1. si se refiere al "concepto" general de la contención de subprocesos y cómo puede presentarse en una aplicación, me refiero a la respuesta detallada de @ DavidSchwartz anterior.

  2. También está el contador de rendimiento '.NET CLR Locks and Threads: Total # of Contentions'. Según la descripción de PerfMon para este contador, se define como:

    Este contador muestra el número total de veces que los subprocesos en CLR han intentado adquirir un bloqueo administrado sin éxito. Las cerraduras gestionadas se pueden adquirir de muchas formas; mediante la instrucción "lock" en C # o llamando a System.Monitor.Enter o utilizando el atributo personalizado MethodImplOptions.Synchronized.

... y estoy seguro de que otros para otros sistemas operativos y marcos de aplicaciones.

Dave Black
fuente
2

Tienes 2 hilos. Thread A y Thread B, también tienes el objeto C.

A está accediendo actualmente al objeto C y ha colocado un candado en ese objeto. B necesita acceder al objeto C, pero no puede hacerlo hasta que A libere el bloqueo del objeto C.

Aaron M
fuente
1

Otra palabra podría ser concurrencia. Es simplemente la idea de dos o más subprocesos que intentan utilizar el mismo recurso.

Mark Wilkins
fuente
1

Para mí, la contención es una competencia entre 2 o más hilos sobre un recurso compartido. El recurso puede ser un candado, un contador, etc. Competencia significa "quién lo obtiene primero". Cuantos más hilos, más contención. Cuanto más frecuente sea el acceso a un recurso, mayor será la contención.

Maciej
fuente
1

Imagina el siguiente escenario. Se está preparando para el examen final de mañana y tiene un poco de hambre. Entonces, le das a tu hermano menor diez dólares y le pides que te compre una pizza. En este caso, usted es el hilo principal y su hermano es un hilo secundario. Una vez que se da su pedido, tanto usted como su hermano están haciendo su trabajo al mismo tiempo (es decir, estudiar y comprar una pizza). Ahora, tenemos dos casos para considerar. Primero, tu hermano trae tu pizza y termina mientras estás estudiando. En este caso, puedes dejar de estudiar y disfrutar de la pizza. En segundo lugar, terminas tu estudio temprano y duermes (es decir, tu trabajo asignado para hoy, estudiar para el examen final de mañana, está terminado) antes de que la pizza esté disponible. Por supuesto, no puedes dormir; de lo contrario, no tendrás la oportunidad de comer la pizza.

Como en el ejemplo, los dos casos dan significado a la rivalidad.

snr
fuente
0

La contención de subprocesos también se ve afectada por las operaciones de E / S. Ejemplo cuando un subproceso en espera de lectura de archivo se puede considerar como una disputa. Utilice los puertos de terminación de E / S como solución.

amilamad
fuente
0

La contención de bloqueo tiene lugar cuando un hilo intenta adquirir el bloqueo de un objeto que ya ha sido adquirido por otro hilo *. Hasta que se libera el objeto, el hilo está bloqueado (en otras palabras, está en estado de espera). En algunos casos, esto puede conducir a una ejecución en serie que afecta negativamente a la aplicación.

de la documentación de dotTrace

AndreyT
fuente