2011-02-27 11 views
11

que estaba leyendo acerca de las nuevas clases de colección concurrentes en .NET 4 en James Michael Hare's blog y el page talking about ConcurrentQueue<T> dice:¿Por qué ConcurrentQueue <T>. Count return 0 cuando IsEmpty == true?

Todavía se recomienda, sin embargo, que para los controles vacíos se llama IsEmpty en lugar de comparar cuenta a cero .

soy curioso - si hay una razón para utilizar IsEmpty en lugar de comparar Conde a 0, ¿por qué la clase no comprueba internamente IsEmpty y volver 0 antes de realizar cualquiera de los trabajos costosos para contar?

ej .:

public int Count 
{ 
    get 
    { 
     // Check IsEmpty so we can bail out quicker 
     if (this.IsEmpty) 
      return 0; 

     // Rest of "expensive" counting code 
    } 
} 

Parece extraño sugerir esto si pudiera ser "fijo" tan fácilmente sin efectos secundarios?

Respuesta

6

Te voy a enseñar una ejemplo exagerar:

public bool IsEmpty 
{ 
    get { /* always costs 10s here */ } 
} 

public int Count 
{ 
    get { /* always costs 15s here, no matter Count is 0 or 1 or 2... */ } 
} 

Si implementan la propiedad Count así:

public int Count 
{ 
    get 
    { 
     if (IsEmpty) return 0; 
     //original implementation here 
    } 
} 

Ahora, cuando el recuento final es 0, cuesta 10s (5s ¡menos que antes !, ¡genial!), pero para aquellos Count es 1/2/más, cuesta más que antes, ¡porque la comprobación de IsEmpty cuesta tiempo! Por lo tanto, la optimización no es una buena idea, porque IsEmpty lleva tiempo. Sería bueno si IsEmpty está leyendo directamente de un campo.

EDITAR he comprobado la implementaion de ambos IsEmpty y Count a través del reflector, ambos son caros . Obviamente, comprobar IsEmpty para 0 conteo reducirá la velocidad de rendimiento promedio.

0

IsEmpty proporciona cierta concurrencia hilo que si obtiene el valor Count y compararlo, está en el hilo, pero la cola podría ser cambiado.

MSDN dice:

Para determinar si la colección contiene ningún artículo, se recomienda el uso de este propiedad en lugar de recuperar el número de elementos de la propiedad Count y comparándolo con 0. Sin embargo, como se pretende acceder a esta colección simultáneamente, puede ocurrir que otro hilo modifique la colección después de IsEmpty devuelve, invalidando así el resultado .

+0

No entiendo lo que quiere decir con "si obtiene el valor de Conteo y lo compara, está en su hilo". ¿Cómo es eso diferente de llamar a IsEmpty? Eso también está en ese hilo. –

+0

Esto es exactamente lo mismo con Count. Si leo Count y devuelve 0, también podría modificarse antes de mi próxima operación. Esto no explica por qué Count internamente no pudo verificar IsEmpty y devolver 0 para evitar este "gotcha". –

+0

O viceversa, esa llamada a IsEmpty en la clase de cola (que está documentada de que Count es O (1)) podría simplemente usar un conteo Count == 0. –

12

ConcurrentQueue<T> está libre de cerrojo y usa espera de centrifugado para lograr un acceso simultáneo de alto rendimiento. La implementación simplemente requiere que se haga más trabajo para devolver el conteo exacto que para verificar si no hay elementos, por lo que se recomienda IsEmpty.

Intuitivamente, puede pensar en Count tener que esperar un lapso de tiempo cuando ningún otro cliente está actualizando la cola, para tomar una instantánea y luego contar los elementos en esa instantánea. IsEmpty simplemente tiene que verificar si hay al menos un artículo o no. Las operaciones concurrentes Enqueue y TryDequeue están cambiando el recuento, por lo que Count tiene que volver a intentarlo; a menos que la cola esté en transición entre los estados vacío y no vacío, las operaciones simultáneas no cambian el valor de retorno de IsEmpty, por lo que no tiene que esperar.

Escribí una aplicación de prueba sencilla de varios subprocesos que mostraba que Count era ~ 20% más lento (con contienda constante y sin contención); sin embargo, ambas propiedades se pueden llamar millones de veces por segundo, por lo que es probable que cualquier diferencia en el rendimiento sea completamente insignificante en la práctica.

+0

Gracias por la información, aunque esto realmente no respondió la pregunta (He actualizado el título para que coincida con la pregunta que puse en el cuerpo): ¿Por qué no (¿no puede?) la implementación de Count tiene "if (this.IsEmpty) return 0 ; " para evitar esta actuación "gotcha"? –

+3

Quizás porque ralentizar cada llamada de Count al esperar potencialmente dos veces para acelerar un caso marginal no es prudente. –

+0

@VirtualBlackFox Por supuesto, esto tiene mucho sentido. Si lo publicas en una respuesta, lo marcaré, en lugar de ocultar la respuesta en un comentario :-) –

0

Comprender cómo funcionan las estructuras concurrentes es muy importante.

if (isEmpty()) ...//do whatever

si tiene estructura concurrente el cheque está cerca de no operación desde todo puede cambiar entre estaVacia y cualquier operación posterior.

Count itera a través de los nodos (no han utilizado C# durante casi 6 años, pero el análogo de Java hace lo mismo) para calcular, por lo que es una llamada costosa. Respuesta directa: La comprobación es Vacía antes del conteo incurrirá en una valla de memoria adicional y no logrará nada. Editar: si no está claro. Cuente cuando la cola está vacía cuesta exactamente como está Vacío, sin embargo, cuesta mucho cuando la cola no es!

Cuenta similar a isEmpty para estructuras concurrentes tiene poco o ningún significado, ya que el resultado de la llamada puede no ser útil y cambiar mucho.

+0

Creo que te perdiste el sentido de la pregunta. Escribir código que usa IsEmpty y Count == 0 tiene un efecto nulo en la concurrencia, ya que todo el bloqueo en estas clases es interno. Mi pregunta era acerca de por qué la propiedad Count no podía revisar IsEmpty de manera interna en lugar de recomendar el uso de IsEmpty. –

+0

@DanTup, tiene efecto, y usted tiene la respuesta, cuesta una barrera de memoria (no está libre). No me perdí el punto. Vuelve a leer la respuesta. – bestsss

+0

@DanTup, se agregó una aclaración adicional, a saber: si la cola es Vacía, el recuento no es costoso (exactamente como Vacío), sin embargo, es – bestsss

Cuestiones relacionadas