Вопрос

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

Это было полезно?

Решение

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

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

Другие советы

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

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

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

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

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

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

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

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

энергозависимые: 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);
});
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top