Когда мне следует использовать ConcurrentDictionary и Dictionary?

Я всегда не понимаю, какой из них выбрать. Насколько я понимаю, я использую Dictionary вместо List, если мне нужны два типа данных как Key и Value, поэтому я могу легко найти значение по его key, но меня всегда путает, следует ли мне использовать ConcurrentDictionary или Dictionary?

Прежде чем вы начнете критиковать меня за то, что я не провел много исследований по этому поводу, я пробовал, но кажется, что у Google действительно нет ничего по Dictionary против ConcurrentDictionary, но есть что-то по каждому в отдельности.

Я уже спрашивал об этом друга раньше, но все они сказали: «Используйте ConcurrentDictionary, если вы часто используете свой словарь в коде», и я действительно не хотел приставать к ним, чтобы объяснить это более подробно. Может ли кто-нибудь расширить это?


person Ashkru    schedule 02.02.2017    source источник
comment
Итак, после просмотра информации по каждому из этих объектов в отдельности, как это не помогло ответить на ваш вопрос о том, когда следует использовать каждый из них? Если вы знаете, когда следует использовать Dictionary, а когда ConcurrentDictionary, учитывая, что вы говорите, что уже нашли эту информацию, тогда вы знаете, когда следует использовать одно вместо другого.   -  person Servy    schedule 03.02.2017
comment
Название как бы объясняет само себя. Вы используете ConcurrentDictionary, когда вам нужен одновременный доступ к словарю.   -  person Scott Chamberlain    schedule 03.02.2017
comment
используйте ConcurrentDictionary, если вы будете обращаться к словарю из нескольких потоков. Вот для чего предназначено все пространство имен System.Collections.Concurrent   -  person Jonesopolis    schedule 03.02.2017
comment
То, что нужно искать, - это безопасность потоков.   -  person Matthew Cawley    schedule 03.02.2017
comment
@Servy, значит, вы говорите, что если бы они знали то, что вы уже знали, им не пришлось бы задавать этот вопрос. Однако они этого еще не знают и поэтому просят. (чтение двух определений не всегда помогает понять разницу)   -  person ctrl-alt-delor    schedule 03.02.2017
comment
Приведенные ниже ответы отчасти неверны, поскольку относятся к «темам». Tasks также должен работать с ConcurrentDictionary.   -  person hyankov    schedule 03.02.2017
comment
@richard Нет, я говорю, что если бы они уже знали то, что они сказали в вопросе, который они уже знали, то они знали бы ответ на вопрос. Легкодоступная информация по каждому типу сделает различия очень очевидными. Если после просмотра этих двух есть какой-то конкретный источник путаницы, тогда должно быть больше, чем, скажите мне разницу, потому что я не побеспокоился, чтобы посмотреть в вопросе, изложив то, что они видели, и почему различия не были очевидны.   -  person Servy    schedule 03.02.2017
comment
@ Серви, ага, понятно. Из ваших рассуждений видно, что вы ошибаетесь, потому что вопрос был задан.   -  person ctrl-alt-delor    schedule 03.02.2017
comment
@richard Это ложное рассуждение. То, что они предпочитают не проводить исследования и не смотреть на различия между двумя типами, не означает, что они не могли этого сделать, просто этого не сделали. Фактически можно задать вопрос, на который вы знаете ответ или на который вы могли бы банально найти ответ. Предположение, что невозможно задать вопрос, на который можно было бы тривиально найти ответ, является ложным.   -  person Servy    schedule 03.02.2017
comment
Я предполагаю, что спрашивающий, вероятно, случайно отфильтровал слова, которые они не поняли (например, одновременные). Поэтому нам нужно помочь со значением этих слов. Не просто говорите, что используйте «одновременное выполнение того, что вам нужно, параллелизм», как сказал Скотт. Поскольку это лингвистический трюизм, его можно вывести из правил английской грамматики. Вероятно, нам нужно объяснить, что означает одновременный доступ, особенно в контексте программирования.   -  person ctrl-alt-delor    schedule 03.02.2017
comment
@richard. Простой поиск этого термина в Интернете даст определение, если они на самом деле не понимают этого слова. Хотя, если бы они заявили, что это то, чего они не понимали, это сделало бы вопрос, по крайней мере, лучше, чем сейчас, хотя это все еще не подходящий вопрос, поскольку этот более подробный вопрос сам легко доступен с помощью простого исследования. Но дело в том, что мы не можем просто сидеть здесь и гадать, что они делают и не понимают. Им нужно задать более конкретный вопрос, объясняя, какие аспекты этого решения они не понимают, отсюда и мой первоначальный вопрос.   -  person Servy    schedule 03.02.2017
comment
@Servy: да, я согласен, и думаю, что мы должны воздерживаться от ответа, пока вопрос не будет ясен, а до тех пор нам нужно выяснить, в чем вопрос, купить, попросив разъяснений.   -  person ctrl-alt-delor    schedule 03.02.2017


Ответы (5)


Используйте ConcurrentDictionary, если вы часто используете свой словарь в коде, это своего рода расплывчатый совет. Я не виню вас в путанице.

ConcurrentDictionary в первую очередь предназначен для использования в среде, где вы обновляете словарь из нескольких потоков (или асинхронных задач). Вы можете использовать стандартный Dictionary из любого количества кода, если он из одного потока;)

Если вы посмотрите на методы в ConcurrentDictionary, вы обнаружите некоторые интересные методы, такие как TryAdd, TryGetValue, TryUpdate и TryRemove.

Например, рассмотрим типичный шаблон, который вы можете увидеть при работе с обычным Dictionary классом.

// There are better ways to do this... but we need an example ;)
if (!dictionary.ContainsKey(id))
    dictionary.Add(id, value);

Проблема заключается в том, что между проверкой наличия ключа и вызовом Add другой поток может вызвать Add с тем же id. Когда этот поток вызывает Add, он генерирует исключение. Метод TryAdd обрабатывает это за вас и возвращает истину / ложь, сообщая вам, добавил ли он его (или этот ключ уже был в словаре).

Поэтому, если вы не работаете в многопоточном разделе кода, вы, вероятно, можете просто использовать стандартный класс Dictionary. При этом теоретически у вас могут быть блокировки для предотвращения одновременного доступа к словарю; этот вопрос уже рассмотрен в Блокировка словаря по сравнению с ConcurrentDictionary.

person Jeff B    schedule 02.02.2017
comment
Спасибо за ответ, очень помогло. Будет ли использование ConcurrentDictionary повсюду, даже если оно исходит из одного потока, настолько плохим? - person Ashkru; 03.02.2017
comment
Можете ли вы использовать непараллельную форму, если вы делаете запись перед созданием потоков (одна многопоточность, только чтение)? Я мог бы представить, что это быстрее, и не могу не понять, как это может сломаться (пока вы не сделаете что-то глупое, например, напишите на него). - person ctrl-alt-delor; 03.02.2017
comment
Вероятно, нет проблем с использованием ConcurrentDictionary, но я предполагаю, что будут по крайней мере некоторые накладные расходы, которые в зависимости от того, как используется словарь, могут быть узким местом. Если вы хотите сравнить источник, чтобы узнать, что происходит, проверьте источник для ConcurrentDictionary.TryAddInternal () и Dictionary.Insert (). - person Jeff B; 03.02.2017
comment
Я предполагаю, что основная цель этого заключается в том, что я не совсем понимаю, когда Решение является многопоточным, означает ли это конкретно его многопоточность, если новый поток создается и запускается программированием, или есть другие вещи, которые делают приложение многопоточным ? Я видел, как он говорил об Async Tasks, есть что-нибудь еще? - person Ashkru; 03.02.2017
comment
Есть много способов сделать потоки. Слишком много, чтобы рассказывать здесь;) - person Jeff B; 03.02.2017
comment
@JeffBridgman, ты имеешь в виду, что если я использую async методы с await внутри, я должен использовать там ConcurrentDictionary? - person Konrad; 26.06.2018
comment
@Konrad Это действительно зависит от вашего конкретного кода и от того, осуществляется ли доступ к словарю из нескольких потоков (таким образом, который может вызвать состояние гонки), поэтому лучший ответ, который я могу дать, может быть: P - person Jeff B; 26.06.2018
comment
@JeffBridgman о, пока он не выйдет из строя и не вызовет состояние гонки, я буду придерживаться словаря. - person Konrad; 26.06.2018

ConcurrentDictionary полезен, когда вам нужно получить доступ к словарю через несколько потоков (например, многопоточность). Объекты Vanilla Dictionary не обладают этой возможностью и поэтому должны использоваться только в однопоточном режиме.

person Woody1193    schedule 02.02.2017
comment
Будет ли использование ConcurrentDictionary повсюду, даже если оно исходит из одного потока, настолько плохим? - person Ashkru; 03.02.2017
comment
Нет, потому что вы запутаете кого-нибудь, читая ваш код позже, если не планируете использовать многопоточность в своей программе. Кроме того, я ожидал бы дополнительных накладных расходов в любой параллельной структуре данных, потому что права доступа должны управляться через несколько потоков. - person Woody1193; 03.02.2017
comment
Вы говорите «нет», тогда продолжайте, как будто это плохо, это плохо? Причина, по которой я спрашиваю, заключается в том, что в настоящее время к нему не получают доступ из других потоков, кроме основного, но это может произойти в будущем. Стоит ли просто использовать Concurrent для обработки всех способов или изменять свой код, если я все же решу реализовать многопоточность? - person Ashkru; 03.02.2017
comment
Я не знаю, каковы ваши конкретные потребности. Я просто демонстрирую плюсы и минусы их использования. Если вы думаете, что в будущем вам может потребоваться многопоточность, и ваш словарь может использоваться в нескольких потоках, то правильным выбором дизайна будет использование ConcurrentDictionary. Однако, если вы не планируете этого делать, вам следует избегать этого, потому что эта структура данных не будет наилучшим образом соответствовать вашим требованиям. - person Woody1193; 03.02.2017

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

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

person Andrew    schedule 02.02.2017
comment
Есть ли недостатки у ConcurrentDictionary с однопоточным кодом? - person Aaron Franke; 22.03.2019
comment
@AaronFranke Overhead, функциональность, обеспечивающая безопасность потоков, будет по-прежнему присутствовать, соответствующие проверки по-прежнему будут выполняться, поэтому это будет более крупный объект, и для работы с ним потребуется больше обработки. Также другие, кто читает код, будут искать потоки и, возможно, будут сбиты с толку. - person Andrew; 22.03.2019

ConcurrentDictionary полезен, когда вам нужен высокопроизводительный словарь, к которому могут безопасно обращаться одновременно несколько потоков. По сравнению со стандартным Dictionary, защищенным с помощью lock, он более эффективен при интенсивном использовании из-за его реализации гранулярной блокировки. Вместо того, чтобы все потоки конкурировали за одну блокировку, ConcurrentDictionary поддерживает несколько блокировок внутри, минимизируя таким образом конкуренцию и ограничивая возможность стать узким местом.

Несмотря на эти приятные характеристики, количество сценариев, в которых использование ConcurrentDictionary является лучшим вариантом, на самом деле довольно мало. На то есть две причины:

  1. Гарантии безопасности потоков, предлагаемые ConcurrentDictionary, ограничиваются защитой его внутреннего состояния. Вот и все. Если вы хотите сделать что-нибудь немного нетривиальное, например, обновить словарь и другую переменную как атомарную операцию, вам не повезло. Этот сценарий не поддерживается для ConcurrentDictionary. Даже защита содержащихся в нем элементов (в случае, если они являются изменяемыми объектами) не поддерживается. Если вы попытаетесь обновить одно из его значений с помощью _ 8_, словарь будет защищен, а значение - нет. Update в этом контексте означает замену существующего значения другим, а не изменение существующего значения.

  2. Всякий раз, когда вы находите соблазн использовать ConcurrentDictionary, обычно доступны лучшие альтернативы. Альтернативы, не связанные с общим состоянием, чем, по сути, является ConcurrentDictionary. Независимо от того, насколько эффективна его схема блокировки, ему будет сложно превзойти архитектуру, в которой вообще нет общего состояния, и каждый поток выполняет свои функции, не мешая другим потокам. Обычно используемые библиотеки, которые следуют этому принципу, - это PLINQ и TPL Dataflow библиотека. Ниже приведен пример PLINQ:

Dictionary<string, Product> dictionary = productIDs
    .AsParallel()
    .Select(id => GetProduct(id))
    .ToDictionary(product => product.Barcode);

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

person Theodor Zoulias    schedule 17.09.2020

Принятый выше ответ правильный. Тем не менее, стоит упомянуть явно, если словарь не изменяется, то есть он только когда-либо читается, независимо от количества потоков, тогда Dictionary<TKey,TValue> предпочтительнее, потому что синхронизация не требуется.

например конфигурация кэширования в Dictionary<TKey,TValue>, который заполняется только один раз при запуске и используется во всем приложении на протяжении всего жизненного цикла приложения.

Когда использовать поточно-ориентированную коллекцию: ConcurrentDictionary или Dictionary

Если вы читаете только ключ или значения, Dictionary ‹TKey, TValue› работает быстрее, потому что не требуется синхронизации, если словарь не изменяется никакими потоками.

person GrantC    schedule 01.04.2021