.net performance interlocked interlocked-increment

.net - Rendimiento de enclavamiento.



performance interlocked (6)

En nuestra experiencia, el InterlockedIncrement () et al en Windows son impactos bastante significativos. En un caso de muestra, pudimos eliminar el bloqueo y utilizar ++ / - en su lugar. Esto solo redujo el tiempo de ejecución de 140 segundos a 110 segundos. Mi análisis es que el enclavamiento fuerza un viaje de ida y vuelta a la memoria (de lo contrario, ¿cómo podrían verlo otros núcleos?). Una lectura / escritura de caché L1 es alrededor de 10 ciclos de reloj, pero una memoria de lectura / escritura más como 100.

En este caso de muestra, estimé el número de operaciones de incremento / decremento en alrededor de 1.000 millones. Entonces, en una CPU de 2 GHz esto es algo así como 5 segundos para el ++ / -, y 50 segundos para el enclavamiento. Difunde la diferencia en varios subprocesos, y está cerca de 30 segundos.

¿Es Interlocked.Increment(ref x) más rápido o más lento que x++ para ints y longs en varias plataformas?


Es más lento ya que obliga a que la acción se produzca de forma atómica y actúa como una barrera de memoria, eliminando la capacidad del procesador para reordenar los accesos de memoria alrededor de la instrucción.

Debería usar Interlocked.Increment cuando desee que la acción sea atómica en un estado que se puede compartir entre subprocesos; no se pretende que sea un reemplazo completo de x ++.


Es mas lento Sin embargo, es la forma general más eficaz que conozco para lograr la seguridad de subprocesos en variables escalares.


Mi prueba de rendimiento:

volátil: 65,174,400

cerradura: 62,428,600

enclavado: 113,248,900

TimeSpan span = TimeSpan.FromSeconds(5); object syncRoot = new object(); long test = long.MinValue; Do(span, "volatile", () => { long r = Thread.VolatileRead(ref test); r++; Thread.VolatileWrite(ref test, r); }); Do(span, "lock", () => { lock (syncRoot) { test++; } }); Do(span, "interlocked", () => { Interlocked.Increment(ref test); });


Piénselo por un momento, y se dará cuenta de que una llamada de Increment no puede ser más rápida que una simple aplicación del operador de incremento. Si lo fuera, entonces la implementación del compilador del operador de incremento llamaría Increment internamente, y realizarían lo mismo.

Pero, como puedes ver al probarlo por ti mismo, no tienen el mismo rendimiento.

Las dos opciones tienen diferentes propósitos. Utilice el operador de incremento en general. Use Increment cuando necesite que la operación sea atómica y está seguro de que todos los demás usuarios de esa variable también están usando operaciones entrelazadas. (Si no todos están cooperando, entonces realmente no ayuda).


Siempre será más lento porque debe realizar un bloqueo de bus de la CPU frente a la actualización de un registro. Sin embargo, las CPU modernas logran un rendimiento cercano al registro, por lo que es insignificante incluso en el procesamiento en tiempo real.