2009-06-16 14 views
11

nos encontramos con problemas de rendimiento, y un posible culpable es el uso centralizado de un singleton volátil. el código específico es de la forma¿Cuál es el costo de la palabra clave volátil en un sistema multiprocesador?

class foo { 
    static volatile instance; 
    static object l = new object(); 

    public static foo Instance { 
    if (instance == null) 
     lock(l) { 
     if (instance == null) 
      instance = new foo(); 
     } 

    return foo(); 
    } 
} 

esto se ejecuta en un cuadro de 8 vías, y estamos viendo el cambio de contexto por una suma de 500.000 por segundo. los recursos típicos del sistema son correctos: 25% de CPU, 25% de memoria de uso, IO bajo, sin paginación, etc.

¿El uso de un campo volátil induce una barrera de memoria o cualquier tipo de recarga de caché de la CPU? ¿o simplemente va detrás de la memoria principal todo el tiempo, solo para ese campo?

+0

no, es una instancia de foo. – kolosy

+0

No estoy seguro de por qué esto tiene que ser volátil, ya que no está cambiando la referencia. –

+0

tampoco, este es el código de alguien que estoy depurando. Sin embargo, mi pregunta principal es si el uso de elementos volátiles podría causar problemas de contención en un cuadro x86 de varios núcleos. – kolosy

Respuesta

4

lock induce una barrera de memoria, por lo que si siempre está accediendo a instancia en un bloqueo no necesita el volátil.

Según this site:

El C# implementos de palabras clave volátiles adquieren y liberan la semántica, lo que implica una barrera de memoria de lectura de leer y una barrera de memoria de escritura en escritura.

+0

no - mira el código. teóricamente, el bloqueo solo ocurrirá una vez, ya que después de eso se establecerá la variable volátil, y la verificación externa pasará. – kolosy

+0

esa edición hace toda la diferencia en el mundo :). Gracias. – kolosy

+1

Vance Morrison también cubre DCL en este artículo de MSDN - http://msdn.microsoft.com/en-us/magazine/cc163715.aspx –

1

Lamentablemente, el singleton tiene una mala reputación para casi todo :)

Ésta no es mi campo de especialización, pero por lo que sé no es nada especial sobre volátil que no sea el compilador/run -time NO reordenar lecturas/escrituras (a la variable) para fines de optimización.

Editar: Estoy corregido. No solo los volátiles introducen barreras de memoria, sino que lo que sucede (y de paso, el rendimiento) depende en gran medida de la CPU particular involucrada. Consulte http://dotnetframeworkplanet.blogspot.com/2008/11/volatile-field-and-memory-barrier-look.html

Es por esto que todavía necesita el candado.

Preguntas que puede/no puede ya han sido contestadas:

  1. ¿Cuál es su instancia singleton realmente hacer? Tal vez el código de instancia debe ser refactorizado ...
  2. ¿Cuál es el conteo de subprocesos del proceso de ejecución? Una caja de 8 vías no lo ayudará si tiene un número de hilos anormalmente alto.
  3. Si es más alto de lo esperado, ¿por qué?
  4. ¿Qué más está funcionando en el sistema?
  5. ¿El problema de rendimiento es constante?
+0

1. no mucho. es un contenedor para algunos datos que deben estar disponibles en todo el mundo 2. el número de subprocesos es adecuado. el cambio de contexto/segundo es ridículamente alto. 500,000/s 3. buena pregunta. 4. nada. 5. sí – kolosy

0

En su ejemplo aquí, volátil no debería ser objeto de ninguna "ralentización". Sin embargo, el bloqueo() puede implicar viajes largos al kernel, especialmente si hay mucha disputa por el bloqueo.

En realidad no hay necesidad de bloquear el singleton en este caso, sólo podría hacerlo

class Foo { 
    static Foo instance = new Foo(); 
    public static Foo FooInstance() { 
    return instance ; 
    } 
} 

Por supuesto, si 'ejemplo' se utiliza en una gran cantidad de diferentes hilos, usted todavía tiene que bloquear() cualquier cosa que altere ese Foo, a menos que todos los métodos/propiedades de Foo sean de solo lectura. p.

class Foo { 
     static Foo instance = new Foo(); 
     object l = new object(); 
     int doesntChange = 42; 
     int canChange = 123; 
     public static Foo FooInstance() { 
     return instance ; 
     } 
     public void Update(int newVal) { 
     lock(l) { // you'll get a lot of trouble without this lock if several threads accesses the same FOO. Atleast if they later on read that variable 
      canChange = newVal; 
     } 

     public int GetFixedVal() { 
     return doesntChange; //no need for a lock. the doesntChange is effectivly read only 
     } 
    } 
0

En realidad no hay necesidad de que el uso de la volátil para un producto único, ya que se está configurando es exactamente una vez - y bloquear el código de los conjuntos de TI. Ver Jon Skeet's article on singletons para más información.

+0

Un DCL sin una barrera de memoria en la lectura es "Tercera versión: intento (y fallo) de seguridad de hilos con bloqueo de doble verificación .. * Sin barreras de memoria, también está quebrado en la especificación ECMA CLI. * ". El código OP es extraño porque puede devolver * multiple * foo's (en lugar de devolver 'instance', que representa un * problema diferente *) .. esta publicación anterior (2006) no indica que un DCL * sin guardias de memoria * es seguro para singletons (de nuevo, un error en el código ...) – user2864740

+0

http://benbowen.blog/post/cmmics_iii/ - vea la nota en ".Net memory model 2.0" 'guarantee'. – user2864740

3

Una cosa que no hace volátil es provocar un cambio de contexto. Si está viendo 500,000 cambios de contexto por segundo, significa que sus hilos están bloqueados en algo y volátil es no el culpable.

0

La respuesta corta es Sí, crea una barrera de memoria (vacía todo y va a la memoria principal, no solo a esa única variable), pero No no será la causa del cambio de contexto.

Además, como han mencionado otros, no creo que la volatilidad sea necesaria aquí.

+0

'volátil' es necesario para * garantizar * seguridad de hilo (no es la única opción, pero es una que se requiere en el patrón de singleton DCL básico). Evita reordenar (y garantiza una lectura "no obsoleta") cuando el código * no * adquiere el bloqueo: si el código * siempre * ingresaba al bloqueo no habría beneficio de 'volátil '. – user2864740

Cuestiones relacionadas