Вложенная блокировка для той же производительности объекта - PullRequest
9 голосов
/ 22 апреля 2010

Стоит ли использовать производительность, чтобы использовать вложенные блокировки для одного и того же объекта.

Скажем, у нас есть:

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

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

Можно ли делать это "на стороне производительности"?1006 *

Заранее спасибо.

Ответы [ 3 ]

7 голосов
/ 22 апреля 2010

Блокировка имеет затраты, я предлагаю вам реализовать свой код следующим образом:

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 голосов
/ 22 апреля 2010

lock не бесплатно. имеет , чтобы проверить определенные вещи, прежде чем вернуться. Сколько вещей и что нужно делать, зависит от реализации. Я бы предположил , что этот вид использования распространен, и MS выполнила некоторую оптимизацию для этого варианта использования.

Я бы по-прежнему рекомендовал, чтобы у вас была отдельная реализация AddRange, в которой все было сделано за один раз. Это, конечно, зависит от остального интерфейса класса (есть ли слушатели и могут ли они получать сообщения о том, что несколько объектов были добавлены и т. Д.).

Это довольно простой тестовый сценарий, сделать несколько миллионов вложенных блокировок (что вы предлагаете) и то же самое с другой блокировкой.

Обратите внимание также на другой возможный порядок, если вы используете не вложенную блокировку, вы можете получить объект в середине диапазона, который вы добавляете:

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

При синхронизации с одним _syncObject никто не может прерывать, поскольку блокировка уже удерживается другим потоком.

1 голос
/ 22 апреля 2010

Я не знаю, как это влияет на производительность, но когда мы ожидаем, что она снизит производительность, я бы посоветовал вам реализовать свой код наоборот:

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 (новый IEnumeratable ({item})): Я не синтаксис wizkid, поэтому, пожалуйста, поправьте меня, если это неправильно!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...