2009-06-23 19 views
20

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

+0

Como otros señalan, no es lo mismo. Dicho esto, de acuerdo con http://msdn.microsoft.com/en-us/magazine/cc163726.aspx un enclavamiento.Incremento toma unos 14nS (o aproximadamente 71'000'000 por segundo) por lo que no me preocuparía mucho sobre el rendimiento – smirkingman

+0

Interlocked.Increment está diseñado para ser utilizado en entornos de subprocesos – EProgrammerNotFound

Respuesta

37

Es más lento ya que fuerza la acción a ocurrir atómicamente y actúa como una barrera de memoria, eliminando la capacidad del procesador para reordenar la memoria accesos alrededor de la instrucción.

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

3

Siempre será más lento porque tiene que realizar un bloqueo de bus de CPU frente a simplemente actualizar un registro. Sin embargo, las CPU modernas alcanzan un rendimiento cercano al registro, por lo que es insignificante incluso en el procesamiento en tiempo real.

+3

Mientras que la CPU X86 realiza un buslock durante las operaciones de interbloqueo, todas las CPU que proporcionan operaciones de enclavamiento no requieren un buslock. Algunas CPU tienen la capacidad de señalar que han reservado una única línea de caché y pueden realizar operaciones entrelazadas en esa línea de caché sin un busbloqueo. – Adisak

4

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

+1

'volátil 'es más eficiente en escalares, pero tiene la desventaja de requerir buenas prácticas de codificación para ser utilizado bien. – Abel

+2

cuidado con volátil; algunas arquitecturas de procesador (x86/x64) tienen la capacidad de reordenar accesos a la memoria, independientemente de si esa memoria fue marcada como volátil para el compilador. –

6

Piénselo un momento y se dará cuenta de que una llamada 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 operador de incremento del compilador llamaría internamente al Increment, y ellos realizarían lo mismo.

Pero, como puede ver probándolo usted mismo, no realizan lo mismo.

Las dos opciones tienen diferentes propósitos. Use 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 interconectadas. (Si no todos cooperan, entonces realmente no ayuda.)

+0

No, no lo haría - Interbloqueado. No se puede invocar el ingreso en una propiedad, mientras que el operador ++ puede hacerlo. Por lo tanto, ++ no podría llamarlo. – SLaks

+0

Para ser más precisos, Increment toma una referencia int (o larga); ++ toma un int (o largo) no ref ( – SLaks

+3

) El compilador ciertamente podría implementar ++ vía Increment. No se implementaría con una simple instrucción de "llamada", pero podría hacerse usando un temporal introducido por el compilador. El punto es que el compilador usa el método de ayuno disponible para incrementar un número; si hubiera algo más rápido, el compilador lo habría usado en su lugar. –

12

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

En este caso de ejemplo, calculé el número de operaciones de incremento/disminución en aproximadamente mil millones. Entonces en una CPU de 2Ghz esto es algo así como 5 segundos para el ++/-, y 50 segundos para el enclavamiento. Extiende la diferencia en varios hilos, y está cerca de 30 segundos.

+5

Micrsoft dice: InterlockedIncrement se midió tomando 36-90 ciclos en http://msdn.microsoft.com/en-us/library/windows/desktop/ee418650(v=vs.85).aspx – Lothar

+1

36 suena bien para no disputado operación, estoy midiendo unas 120 veces para una operación muy controvertida en un Core i7, pero tal vez lo fallé? De todos modos, "el enclavamiento obliga a una ida y vuelta de memoria (de lo contrario, ¿cómo podrían verlo otros núcleos?). Una lectura/escritura de caché L1 es de alrededor de 10 ciclos de reloj ...": basta marcar esa página como modificada y solo vaciar de L1 a la memoria si otro núcleo necesita verlo, entonces la operación no impugnada puede estar más cerca del extremo 10 del espectro (en 36) en lugar de 100 + ... –

4

Mi prueba del perfomance:

volátil: 65174400

bloqueo: 62428600

entrelazados: 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); 
}); 
+2

¿Qué es 'Hacer'? – SLaks

+0

Se ejecuta el método n veces hasta que se haya alcanzado el intervalo de tiempo – MastsrOfDesaster

+3

Entonces, espere, ¿hay algo mejor en este caso? ¿Podría especificar cuáles son sus métricas? –

Cuestiones relacionadas