Насколько дорогой оператор блокировки? - PullRequest
97 голосов
/ 12 января 2011

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

private object mutex = new object();

public void Count(int amount)
{
 lock(mutex)
 {
  done += amount;
 }
}

Но мне было интересно ... сколько стоит блокировка переменной? Каковы негативные последствия для производительности?

Ответы [ 7 ]

71 голосов
/ 12 января 2011

Вот статья , которая входит в стоимость. Краткий ответ 50 нс.

48 голосов
/ 12 января 2011

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

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

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

25 голосов
/ 27 сентября 2015

Дальнейшее чтение:

Я хотел бы представить несколько моих статей, которые интересуются общими примитивами синхронизации, и они углубляются в Monitor, поведение оператора C # lock, свойства и затраты в зависимости от различных сценариев иколичество потоков.Он особенно заинтересован в потерях ЦП и периодах пропускной способности, чтобы понять, сколько работы можно выполнить в нескольких сценариях:

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

Оригинальный ответ:

О, дорогой!

Кажется, что правильный ответ, помеченный здесь как ОТВЕТ, по своей сути неверен!Я хотел бы попросить автора ответа, с уважением, прочитать связанную статью до конца. article

Автор статьи 2003 article проводил измерения только на двухъядерной машине, а в первом случае он измерял блокировку с помощью одноготолько для потока , и результат составил около 50 нс на блокировку доступа.

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

Итак, автор говорит, что с двумяна двухъядерных процессорах, блокировки стоят 120 нс, а с 3-мя потоками - до 180 нс.Таким образом, кажется, что он явно зависит от количества потоков, одновременно обращающихся к блокировке.

Так что все просто, это не 50 нс, если это не один поток, где блокировка становится бесполезной.

Еще одна проблема для рассмотрения состоит в том, что она измеряется как среднее время !

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

Это плохие новости для любого типа приложений, требующих высокой пропускной способности и низкой задержки.

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

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

20 голосов
/ 12 января 2011

Это не отвечает на ваш запрос о производительности, но я могу сказать, что .NET Framework действительно предлагает метод Interlocked.Add, который позволит вам добавить amount к вашему done элемент без ручной блокировки другого объекта.

10 голосов
/ 12 января 2011

lock (Monitor.Enter / Exit) очень дешево, дешевле, чем альтернативы, такие как Waithandle или Mutex.

Но что, если это будет (немного) медленно, вы бы предпочли быструю программу с неверными результатами?

6 голосов
/ 29 сентября 2013

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

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LockPerformanceConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            var stopwatch = new Stopwatch();
            const int LoopCount = (int) (100 * 1e6);
            int counter = 0;

            for (int repetition = 0; repetition < 5; repetition++)
            {
                stopwatch.Reset();
                stopwatch.Start();
                for (int i = 0; i < LoopCount; i++)
                    lock (stopwatch)
                        counter = i;
                stopwatch.Stop();
                Console.WriteLine("With lock: {0}", stopwatch.ElapsedMilliseconds);

                stopwatch.Reset();
                stopwatch.Start();
                for (int i = 0; i < LoopCount; i++)
                    counter = i;
                stopwatch.Stop();
                Console.WriteLine("Without lock: {0}", stopwatch.ElapsedMilliseconds);
            }

            Console.ReadKey();
        }
    }
}

Выход:

With lock: 2013
Without lock: 211
With lock: 2002
Without lock: 210
With lock: 1989
Without lock: 210
With lock: 1987
Without lock: 207
With lock: 1988
Without lock: 208
4 голосов
/ 12 января 2011

Есть несколько разных способов определения «стоимости».Существуют накладные расходы на получение и снятие блокировки;как пишет Джейк, это незначительно, если эта операция не выполняется миллионы раз.

Более важным является влияние, которое это оказывает на ход выполнения.Этот код может быть введен только одним потоком за раз.Если у вас есть 5 потоков, выполняющих эту операцию на регулярной основе, 4 из них в конечном итоге ожидают снятия блокировки, а затем станут первым потоком, запланированным для ввода этого фрагмента кода после снятия блокировки.Итак, ваш алгоритм сильно пострадает.Насколько это зависит от алгоритма и от того, как часто вызывается операция. Вы не можете избежать этого, не вводя условия гонки, но вы можете улучшить его, сводя к минимуму количество обращений к заблокированному коду.

...