A continuación se muestra una implementación de un método entrelazado basado en Interlocked.CompareExchange
.
¿Es aconsejable que este código use un SpinWait
giro antes de reiterar?
public static bool AddIfLessThan(ref int location, int value, int comparison)
{
int currentValue;
do
{
currentValue = location; // Read the current value
if (currentValue >= comparison) return false; // If "less than comparison" is NOT satisfied, return false
}
// Set to currentValue+value, iff still on currentValue; reiterate if not assigned
while (Interlocked.CompareExchange(ref location, currentValue + value, currentValue) != currentValue);
return true; // Assigned, so return true
}
Lo he visto SpinWait
usado en este escenario, pero mi teoría es que debería ser innecesario. Después de todo, el bucle solo contiene un puñado de instrucciones, y siempre hay un hilo que avanza.
Digamos que dos hilos están compitiendo para realizar este método, y el primer hilo tiene éxito de inmediato, mientras que el segundo hilo inicialmente no hace ningún cambio y tiene que reiterar. Sin otros contendientes, ¿es posible que el segundo hilo falle en su segundo intento ?
Si el segundo hilo del ejemplo no puede fallar en el segundo intento, ¿qué podríamos ganar con un SpinWait
? ¿Afeitarse algunos ciclos en el improbable caso de que cientos de hilos compitan para realizar el método?
SpinOnce
para evitar que un sistema operativo de un solo subproceso se vea potencialmente hambriento. Ver stackoverflow.com/questions/37799381/…Interlocked
. Para aclarar, solo me interesa saber si aSpinWait
tiene sentido o no , por ejemplo, para ahorrar significativamente los ciclos de la CPU o (¡gracias @MatthewWatson!) Evitar que un sistema operativo de un solo subproceso se muera de hambre.SpinWait
eso ni siquiera reduzca el consumo de energía, ya que de todos modos se realizará el mismo número de intentos. (Con dos hilos, ese es un intento para el primero y dos para el segundo hilo.)Respuestas:
Mi opinión no experta es que en este caso particular, donde dos hilos ocasionalmente llaman
AddIfLessThan
, aSpinWait
es innecesario. Podría ser beneficioso en el caso de que los dos hilos estuvieran llamandoAddIfLessThan
en un bucle cerrado, de modo que cada hilo pudiera avanzar sin interrupciones durante algunos μseg.En realidad hice un experimento y medí el rendimiento de una llamada de hilo
AddIfLessThan
en un bucle cerrado frente a dos hilos. Los dos hilos necesitan casi cuatro veces más para hacer la misma cantidad de bucles (acumulativamente). AgregarSpinWait
a la mezcla hace que los dos hilos sean solo un poco más lentos que el hilo único.fuente
SpinWait
dentro delAddIfLessThan
método, y aunque es un tipo de valor y suSpinOnce
método nunca se llama, todavía agrega algo de sobrecarga.Dos hilos no es un tema de
SpinWait
discusión. Pero este código no nos dice cuántos hilos pueden realmente competir por el recurso y con un número relativamente alto de hilosSpinWait
puede ser beneficioso. En particular, con un mayor número de subprocesos, la cola virtual de subprocesos, que intentan adquirir con éxito el recurso, se alarga y los subprocesos que finalmente se atienden tienen buenas posibilidades de exceder su intervalo de tiempo asignado por el planificador, que a su vez puede conducir a un mayor consumo de CPU y puede afectar la ejecución de otros subprocesos programados incluso con mayor prioridad. losSpinWait
tiene una buena respuesta a esta situación estableciendo un límite superior de giros permitidos después de lo cual se va a ejecutar el cambio de contexto. Por lo tanto, es una compensación razonable entre la necesidad de realizar una costosa llamada al sistema para activar un cambio de contexto y un consumo de CPU en modo de usuario no controlado, que corre el riesgo de afectar la ejecución de otros hilos en ciertas situaciones.fuente
SpinWait
exageración o no?SpinWait
estrategia es mejor (con un costo relativamente pequeño de docenas de microsegundos) que no usar eso a menos que excluya de antemano la posibilidad de escenarios de alta carga baja, por lo que encontrar un punto de carga en el que el rendimiento pueda estar afectado le daría una pista de si lo necesita o no (tenga en cuenta que también puede depender de la cantidad de núcleos).SpinWait
agrega valor. Hasta ahora, esos parecen ser (A) el caso de un solo núcleo, y (B) posiblemente el caso de contención muy alta.