Я экспериментировал с многопоточностью и параллельной обработкой, и мне нужен был счетчик для базового подсчета и статистического анализа скорости обработки. Чтобы избежать проблем с одновременным использованием моего класса, я использовал оператор блокировки для частной переменной в моем классе:
private object mutex = new object();
public void Count(int amount)
{
lock(mutex)
{
done += amount;
}
}
Но мне было интересно ... насколько дорого обходится блокировка переменной? Какое негативное влияние на производительность?
c#
.net
multithreading
locking
parallel-processing
Кис К. Баккер
источник
источник
Ответы:
Вот статья, в которой рассказывается о стоимости. Короткий ответ - 50 нс.
источник
lock
больше, чем о стоимости использования переменной.Технический ответ заключается в том, что это невозможно количественно оценить, это сильно зависит от состояния буферов обратной записи памяти ЦП и от того, сколько данных, собранных устройством предварительной выборки, необходимо отбросить и перечитать. Оба они очень недетерминированы. Я использую 150 циклов процессора в качестве приблизительного приближения, которое позволяет избежать серьезных разочарований.
Практический ответ заключается в том, что это намного дешевле, чем время, которое вы потратите на отладку кода, когда вы думаете, что можете пропустить блокировку.
Чтобы получить точное число, вам нужно будет измерить. В Visual Studio есть удобный анализатор параллелизма, доступный как расширение.
источник
Дальнейшее чтение:
Я хотел бы представить несколько моих статей, которые интересуются общими примитивами синхронизации, и они углубляются в Monitor, поведение оператора блокировки C #, свойства и затраты в зависимости от различных сценариев и количества потоков. Его особенно интересуют потери ЦП и периоды пропускной способности, чтобы понять, какой объем работы можно выполнить в нескольких сценариях:
https://www.codeproject.com/Articles/1236238/Unified-Concurrency-I-Introduction https://www.codeproject.com/Articles/1237518/Unified-Concurrency-II-benchmarking-methodologies https: // www. codeproject.com/Articles/1242156/Unified-Concurrency-III-cross-benchmarking
Оригинальный ответ:
О, Боже!
Кажется, что правильный ответ, отмеченный здесь как ОТВЕТ, по своей сути неверен! С уважением прошу автора ответа прочитать связанную статью до конца. статья
Автор статьи из 2003 статьи измерял только на Dual Core машины и в первом измерительном случае он измеряется замок только с одним потоком , и результат был примерно 50ns за доступ замка.
Он ничего не говорит о блокировке в параллельной среде. Итак, мы должны продолжить чтение статьи, и во второй половине автор измерял сценарий блокировки с двумя и тремя потоками, который приближается к уровням параллелизма современных процессоров.
Итак, автор говорит, что с двумя потоками на Dual Core блокировки стоят 120 нс, а с 3 потоками - до 180 нс. Таким образом, это явно зависит от количества потоков, одновременно обращающихся к блокировке.
Это просто, это не 50 нс, если только это не один поток, где блокировка становится бесполезной.
Другой вопрос, требующий внимания, - это то, что оно измеряется как среднее время !
Если бы время итераций было измерено, было бы даже время от 1 мс до 20 мс, просто потому, что большинство из них было быстрым, но немногие потоки будут ждать времени процессора и будут иметь длительные задержки даже в миллисекунды.
Это плохая новость для любого приложения, которому требуется высокая пропускная способность и низкая задержка.
И последний вопрос, который следует учитывать, заключается в том, что внутри блокировки могут выполняться более медленные операции, и очень часто это так. Чем дольше блок кода выполняется внутри замка, тем выше конкуренция, а задержки растут до небес.
Учтите, что с 2003 года прошло уже более одного десятилетия, то есть несколько поколений процессоров, разработанных специально для работы полностью одновременно, и блокировка значительно снижает их производительность.
источник
Это не отвечает на ваш вопрос о производительности, но я могу сказать, что .NET Framework действительно предлагает
Interlocked.Add
метод, который позволит вам добавитьamount
вашdone
член в свой член без ручной блокировки другого объекта.источник
lock
(Monitor.Enter / Exit) очень дешево, дешевле, чем альтернативы, такие как Waithandle или Mutex.Но что, если бы она была (немного) медленной, вы бы предпочли быструю программу с неверными результатами?
источник
Стоимость блокировки в замкнутом контуре по сравнению с альтернативой без блокировки огромна. Вы можете позволить себе повторять цикл много раз и при этом быть более эффективным, чем блокировка. Вот почему очереди без блокировки так эффективны.
Вывод:
источник
Есть несколько разных способов определить «стоимость». Есть фактические накладные расходы на получение и снятие блокировки; как пишет Джейк, это ничтожно мало, если эта операция не выполняется миллионы раз.
Более важно то, как это влияет на ход выполнения. Этот код может быть введен только одним потоком за раз. Если у вас есть 5 потоков, выполняющих эту операцию на регулярной основе, 4 из них в конечном итоге будут ждать снятия блокировки, а затем станут первым потоком, запланированным для ввода этого фрагмента кода после снятия этой блокировки. Итак, ваш алгоритм значительно пострадает. Насколько это зависит от алгоритма и от того, как часто вызывается операция. Вы не можете избежать этого, не вводя состояния гонки, но вы можете улучшить это, минимизировав количество вызовов заблокированного кода.
источник