2010-04-22 16 views
8

¿Es un costo de rendimiento utilizar bloqueos anidados para el mismo objeto?Bloqueo anidado al mismo rendimiento del objeto

Digamos que tenemos:

public void AddRange(IEnumeratable<Item> items) 
    { 
     lock (_syncObject) 
     { 
      foreach (Item item in items) 
      { 
       InsertItem(item); 
      } 
     } 
    } 

    public void InsertItem(Item item) 
    { 
     lock (_syncObject) 
     { 
      //.. 
     } 
    } 

¿Está bien para hacerlo "cuanto al rendimiento"?

Gracias de antemano.

Respuesta

6

bloqueo tiene costos, le sugiero que para implementar su código como este:

public void AddRange(IEnumeratable<Item> items) 
{ 
    lock (_syncObject) // Locking only once. 
    { 
     foreach (Item item in items) 
     { 
      InsertItemImpl(item); 
     } 
    } 
} 

private void InsertItemImpl(Item item) 
{ 
    // inserting the item 
} 

public void InsertItem(Item item) 
{ 
    lock (_syncObject) 
    { 
     InsertItemImpl(item); 
    } 
} 
2

lock no es gratis. es tiene para verificar ciertas cosas antes de regresar. Cuántas cosas y qué tiene que hacer, depende de la implementación. Me gustaría suponer que este tipo de uso es común y MS hizo algo de optimización para este uso.

Aún recomiendo que tenga una implementación separada de AddRange con todas las cosas hechas de una vez. Esto, por supuesto, depende del resto de la interfaz de la clase (¿hay oyentes y pueden recibir mensajes de que se agregaron varios objetos, etc.)?

Esto es bastante fácil de usar, hacer algunos millones de bloqueo anidado (lo que usted propone) y lo mismo con otro bloqueo.

Nótese también la diferente orden posible si utiliza el bloqueo no anidada, puede obtener un objeto en medio de un rango que va a añadir:

AddRange _sync1 
    AddItem _sync2 
    AddItem _sync2 
    --- interruption, other thread calls: 
    AddItem _sync2 
    --- AddRange again: 
    AddItem _sync2 

Al sincronizar con un único _syncObject, nadie puede interrumpir porque el bloqueo ya está retenido por otro hilo.

1

No sé cómo el rendimiento se ve afectado, pero cuando se espera que disminuya el rendimiento me gustaría sugerir a implementar su código al revés:

public void InsertItem(Item item) 
{ 
    AddRange(new IEnumeratable({item})) 
} 

public void AddRange(IEnumeratable<Item> items) 
{ 
    lock (_syncObject) 
    { 
     foreach (Item item in items) 
     { 
      // Insert code .. 
     } 
    } 
} 

@AddRange (nueva IEnumeratable ({ item})): No soy un sintaxis de wizkid así que por favor corrígeme si esto no está bien.

+3

creo que es mejor mover a cabo la implementación de inserción a otro método en lugar de crear una nueva colección para cada elemento de la adición. –

Cuestiones relacionadas