Блокировка C # с запросом LINQ - PullRequest
8 голосов
/ 07 июня 2011

Необходимо ли блокировать операторы LINQ следующим образом?Если исключить блокировку, любые исключения будут отменены, если несколько потоков выполнят ее одновременно?

lock (syncKey)
{
    return (from keyValue in dictionary
            where keyValue.Key > versionNumber
            select keyValue.Value).ToList();
}

PS: Writer существуют потоки для изменения словаря.

Ответы [ 4 ]

5 голосов
/ 07 июня 2011

Пока запрос не имеет побочных эффектов (таких как выражения, вызывающие код, который вносит изменения), нет необходимости блокировать оператор LINQ.

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

Если вы используете .NET 4.0, и существует ConcurrentDictionary, который является потокобезопасным. Вот пример использования параллельного словаря (по общему признанию, не в выражении LINQ)

ОБНОВЛЕНИЕ

Если вы изменяете данные, тогда вам нужноиспользовать замки.Если два или более потоков попытаются получить доступ к заблокированному разделу кода, произойдет небольшая потеря производительности, поскольку один или несколько потоков ожидают снятия блокировки.ПРИМЕЧАНИЕ. Если вы перегружаете блокировку, то вы можете получить худшую производительность, чем если бы вы только что создали код с использованием последовательного алгоритма с самого начала.

Если вы только когда-либо читаете данные, то вы не 'не нужны блокировки, так как нет изменяемого общего состояния для защиты.

Если вы не используете блокировки, то вы можете столкнуться с периодически возникающими ошибками, когда данные не совсем верны или возникают исключения, когда возникают конфликты между читателями и писателями.По моему опыту, в большинстве случаев вы можете никогда не получить исключение, вы просто получаете поврежденные данные (за исключением того, что вы не обязательно знаете, что они повреждены).Вот еще один пример, показывающий , как данные могут быть повреждены, если вы не используете блокировки или не перепроектируете свой алгоритм, чтобы справиться с .

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

4 голосов
/ 07 июня 2011

Большинство типов являются поточно-ориентированными для чтения , но не поточнобезопасными во время мутации.

Если ни один из потоков не изменяет словарь, то выне нужно делать что-нибудь - просто читать.

Если, однако, один из потоков меняет , то у вас есть проблемы и вам нужно выполнить синхронизацию.Самый простой подход - это lock, однако это предотвращает одновременное чтение, даже когда нет писателя.Если есть большая вероятность, что у вас будет больше читателей, чем писателей, рассмотрите возможность использования ReaderWriterLockSlim для синхронизации - это позволит любому числу читателей (без писателя) или: одному писателю.

В 4.0 выможет также рассмотреть ConcurrentDictionary<,>

2 голосов
/ 07 июня 2011

Если ваш словарь статический, а метод, в котором вы выполняете запрос, - нет (или другой сценарий одновременного доступа), и словарь можно изменить из другого потока, тогда да, блокировка требуется в противном случае - нет.

1 голос
/ 07 июня 2011

Да, вам нужно заблокировать ваши общие ресурсы при использовании LINQ в многопоточных сценариях (РЕДАКТИРОВАТЬ: конечно, если ваша исходная коллекция изменяется, как сказал Марк, если вы только читаете ее, вам не нужно беспокоиться об этом). Если вы используете .Net 4 или параллельные расширения для 3.5, вы можете заменить словарь на ConcurrentDictionary (или использовать какую-либо другую пользовательскую реализацию в любом случае).

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