блокировка против AcquireReader и блокировка записи

2

Я нашел возможное замедление в моем приложении, поэтому у меня было бы два вопроса:

  • Какова реальная разница между простой блокировкой объекта и блокировкой чтения/записи? Например. У меня есть коллекция клиентов, которые быстро меняются. Для итераций следует использовать считыватель или достаточно простого замка?
  • Чтобы уменьшить нагрузку, я оставил итерацию (только чтение) одной коллекции без каких-либо блокировок. Эта коллекция меняется часто и быстро, но элементы добавляются и удаляются с помощью writerlocks. Является ли это безопасным (я не пропущу случайного пропущенного элемента, этот метод работает в цикле и его не критично), чтобы оставить это чтение незащищенным блокировкой? Я просто не хочу иметь случайные исключения.
Теги:
multithreading
locking

2 ответа

2
Лучший ответ

Нет, ваш текущий сценарий небезопасен.

В частности, если коллекция изменяется во время повтора по ней, вы получите InvalidOperationException в итерационном потоке. Вы должны получить блокировку читателя на протяжении всего итератора:

  • Получить блокировку считывателя
  • Итерации по коллекции
  • Блокировка устройства чтения

Обратите внимание, что это не то же самое, что получение блокировки чтения для каждого шага итерации - это не поможет.

Что касается разницы между блокировками чтения/записи и "нормальными" блокировками - идея блокировки чтения/записи заключается в том, что одновременно могут считываться несколько потоков, но только один поток может писать (и только тогда, когда нет ни одного читает). В некоторых случаях это может повысить производительность - но это также увеличивает сложность решения (с точки зрения его правильности). Я бы посоветовал вам использовать ReaderWriterLockSlim из .NET 3.5, если возможно, - он намного эффективнее исходного ReaderWriterLock, и есть некоторые проблемы с ReaderWriterLock IIRC.

Лично я обычно использую простые блокировки, пока не доказал, что конфликт блокировок является узким местом производительности. Профилировали ли вы свое приложение еще, чтобы узнать, где находится узкое место?

  • 0
    Спасибо! Просто один простой вопрос - я видел несколько кодов, в которых были разные экземпляры блокировки чтения или записи для каждой коллекции. Почему? Разве не хватит иметь один и назвать его над нужным объектом? На ваш вопрос: да, но результаты профилировщика были не очень конкретными. Но из вашей информации я думаю, что мне нужно использовать блокировки чтения / записи вместо простых блокировок, из-за многопоточной природы приложения, где часто требуется чтение рекламы для записи в одну и ту же коллекцию.
  • 3
    блокировки чтения / записи работают лучше всего, когда есть: а) множество различных потоков, б) большинство операций - чтение. Если у вас есть, скажем, только одно чтение потока и одна (или более) запись потока, а коллекция часто обновляется, то блокировка чтения / записи вообще не приносит никакой пользы.
Показать ещё 2 комментария
2

Хорошо сначала про чтение итерации без блокировки. Это не безопасно, и вы не должны этого делать. Просто, чтобы проиллюстрировать суть самым простым способом - вы повторяете сборку, но вы никогда не знаете, сколько предметов в этой коллекции и не имеют способа узнать. Где вы остановились? Проверка подсчета каждой итерации не помогает, потому что она может измениться после проверки, но прежде чем вы получите элемент.

ReaderWriterLock предназначен для ситуации, когда вы разрешаете нескольким потокам иметь одновременный доступ для чтения, но принудительно синхронно записывайте. Из звуков вашего приложения у вас нет нескольких одновременных считывателей, и записи так же распространены, как и чтение, поэтому ReaderWriterLock не дает никакой пользы. В этом случае вам будет лучше служить классическая блокировка.

В целом, крошечные преимущества в производительности, которые вы вытесняете из-за неблокирующего доступа к общим объектам с многопотоковой обработкой, резко компенсируются случайной странностью и необъяснимым поведением. Заблокируйте все, что является общим, протестируйте приложение, а затем, когда все будет работать, вы можете запустить профайлер, проверьте, сколько времени приложение ожидает блокировок, а затем при необходимости реализует некоторые опасные трюки. Но шансы на то, что воздействие будет небольшим.

"Мы должны забыть о небольшой эффективности, скажем, около 97% времени: преждевременная оптимизация - это корень всего зла. Но мы не должны упускать наши возможности в этих критических 3%. Хороший программист не будет быть убаюканным до самоуспокоения такими рассуждениями, он будет разумно внимательно смотреть на критический код, но только после того, как этот код был идентифицирован" - Дональд Кнут

Ещё вопросы

Сообщество Overcoder
Наверх
Меню