Подтвердить что ты не робот

Выполнение блокировки.

Является ли Interlocked.Increment(ref x) быстрее или медленнее, чем x++ для ints и longs на разных платформах?

4b9b3361

Ответ 1

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

Вы должны использовать Interlocked.Increment, когда вы хотите, чтобы действие было атомарным в состоянии, которое может быть разделено между потоками - оно не предназначено для полной замены для x ++.

Ответ 2

По нашему опыту, InterlockedIncrement() и др. в Windows являются довольно значительными последствиями. В одном примере мы смогли устранить блокировку и вместо этого использовать ++/-. Это позволило сократить время работы от 140 секунд до 110 секунд. Мой анализ заключается в том, что блокировка принудительно перемещает память в другую сторону (иначе, как могли бы другие ядра увидеть это?). Чтение/запись кеша L1 составляет около 10 тактов, но память читает/записывает больше, чем 100.

В этом примере я оценил количество операций приращения/декремента около 1 миллиарда. Так что на 2 ГГц CPU это что-то вроде 5 секунд для ++/- и 50 секунд для блокировки. Распространяйте разницу между несколькими потоками, а ее значение составляет около 30 секунд.

Ответ 3

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

Но, как вы можете видеть, тестируя его для себя, они не выполняют то же самое.

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

Ответ 4

Это медленнее. Тем не менее, это самый эффективный общий способ, который я знаю для обеспечения безопасности потоков для скалярных переменных.

Ответ 5

Мое тестирование производительности:

volatile: 65,174,400

блокировка: 62 428 600

взаимосвязано: 113 248 900

TimeSpan span = TimeSpan.FromSeconds(5);

object syncRoot = new object();
long test = long.MinValue;

Do(span, "volatile", () => {

    long r = Thread.VolatileRead(ref test);

    r++;

    Thread.VolatileWrite(ref test, r);
});

Do(span, "lock", () =>
{
    lock (syncRoot)
    {
        test++;
    }
});

Do(span, "interlocked", () =>
{
    Interlocked.Increment(ref test);
});

Ответ 6

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