0

У меня есть словарь, который я хотел бы изменить его значения в цикле foreach, однако, поскольку мое приложение имеет решающее значение для времени, я пытаюсь избегайте всех ненужных накладных расходов на блокировку.Является ли безопасным для записей словаря r/w в Parallel.ForEach в C#

Является ли маркированная команда безопасной? то есть читать/записывать разные пары ключ-значение словаря без блокировки.

Примечание 1: Я знаю о пространстве имен совпадающих коллекций и всех его великолепных коллекций. Также я знаю, что я могу просто выделить выделенную команду, чтобы обеспечить ее безопасность. Как указано выше, моя цель избегает ненужных накладных расходов в максимально возможной степени.

Примечание 2: Вопрос такой же вопрос at this link. В этом вопросе элементы контейнера изменяются внутри цикла Parallel.ForEach. Принимая во внимание, что здесь мы не изменяем пары ключ-значение, поэтому контейнер не поврежден, изменяются только данные, указывающие. Это отличает его от вышеупомянутого вопроса.

Update

  1. Этот код работает отлично, без блокировки, но я должен быть уверенным.
  2. Eventough ConcurrentDictionary добавит наименее возможные накладные расходы, я бы хотел избежать этого, если это безопасно.
+0

Что вы пробовали? Что работает и что не работает? Вы измеряли какие-либо проблемы с производительностью при использовании ConcurrentDictionary? Операция добавления должна быть довольно быстрой и не проблема, если задача «манипулировать списком» занимает некоторое время. –

+0

Вероятный дубликат http://stackoverflow.com/questions/5605422/is-this-use-of-parallel-foreach-thread -safe –

+0

попробуйте добавить 1000 строк в loopData и посмотреть, правильно ли он передает результаты. –

ответ

8

Безопасно читать из словаря одновременно, но небезопасно записывать его одновременно или читать из него во время записи одновременно. ConcurrentDictionary будет вашим самым быстрым вариантом для одновременных вставок.

+0

Я согласен с вами, и я подозревал безопасность, поэтому я задал вопрос. Однако, все же я не уверен, почему это не безопасно? Каждое значение представляет собой совершенно другой элемент, независимо от остальных, и словарь имеет только указатель на этот экземпляр, поэтому почему изменение одного экземпляра компрометирует безопасность другого экземпляра? – Hamed

+0

@Hamed: изменение переменной 'list' безопасно, но вы запросили операцию' .Add() '. И это даст вам ошибки, такие как '" Целевой массив не был достаточно длинным. Проверьте destIndex и длину и нижние границы массива. "' –

+1

@Hamed, потому что [внутренний словарь - это просто большая запись [] [];] (http : //referencesource.microsoft.com/#mscorlib/system/collections/generic/dictionary.cs,d3599058f8d79be0), и он использует специальную логику, чтобы выяснить, где в массиве писать или читать. Если вы добавляете больше элементов, чем размер 'entries', он должен изменить размер массива. Если два потока пытаются писать одновременно, в то время как происходит изменение размера, происходят плохие вещи. –

1

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

Parallel.ForEach(loopData, data => 
{ 
    var list = data.Value;  //<-- this is safe, because a read operation 
    /// manipulate list here  <-- this is safe, because it operates on individual objects 

    /// Is this safe?    <-- no, this is a write access 
    results[data.Key] = list; 
}); 

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

+0

Спасибо за разъяснение, хотя это было ясно :) – Hamed