2013-12-22 2 views
2

Я тестировал, как Interlocked.Increment и lock ведут себя на архитектуре моего компьютера, потому что я прочитал следующие строки в this article.Interlocked.Increment vs lock в debug vs mode mode

Как было переписано с помощью блокировки. Метод должен выполняться быстрее, по крайней мере, на некоторых архитектурах.

Используя следующий код, я убедился, что стоит рассмотреть блокировки в моих проектах.

var watch = new Stopwatch(); 
var locker = new object(); 
int counter = 0; 

watch.Start(); 
for (int i = 0; i < 100000000; i++) 
{ 
    lock (locker) 
    { 
     counter++; 
    } 
} 
watch.Stop(); 
Console.WriteLine(watch.Elapsed.TotalSeconds); 

watch.Reset(); 
counter = 0; 

watch.Start(); 
for (int i = 0; i < 100000000; i++) 
{ 
    Interlocked.Increment(ref counter); 
} 
watch.Stop(); 
Console.WriteLine(watch.Elapsed.TotalSeconds); 

Я получаю стабильные результаты с приближенными значениями 2.4s для запирания и 1.2s для ВЗАИМОСВЯЗАННОГО. Однако я с удивлением обнаружил, что запуск этого кода в режиме освобождения улучшает значение только для блокировки приблизительно до 0,7 с, и время блокировки остается неизменным. Почему это? Как блокируется оптимизация, когда в режиме деблокирования блокировки нет?

+1

Как правило, все измерения производительности должны выполняться только в режиме деблокирования. Измерения производительности режима отладки не актуальны. Прочитайте MSIL, предоставленный компилятором C#, возможно, код слишком оптимизирован (например, Interlocked заменяется на ++). –

+1

Для незащищенной области блокировки требуются две взаимосвязанные инструкции. Показанные вами цифры показывают это идеально, по крайней мере, в режиме отладки. Кстати, ваш бенчмарк означает очень мало, потому что стоимость синхронизации зависит от конкуренции и ограничений в отношении кэш-линии. Ваш ориентир предполагает, что его нет. – usr

+0

@usr Было бы здорово, если бы вы могли написать больше об этом и опубликовать его в качестве ответа. Я не понимаю MSIL, как предлагает Алекс, и с тех пор, как я прочитал всю статью, и это я до сих пор не понимаю полностью, более подробная информация по этой теме будет приветствоваться. –

ответ

3

Вы должны посмотреть на сгенерированный машинный код, чтобы увидеть разницу, Отладка + Windows + Разборка. Отладочная версия билд (вызов Interlocked.Increment):

00FC27AD call  7327A810 

версия релиз сборки:

025F279D lock inc dword ptr [ebp-24h] 

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

Оптимизация только не улучшается. Та же оптимизация не может применяться к вызову метода Monitor.Enter(), который находится под оператором lock, это довольно существенная функция, реализованная в среде CLR и не может быть встроена. Он выполняет многие функции, кроме Interlocked.Increment(), позволяет операционной системе перепланировать, когда поток блокируется при попытке получить монитор и поддерживает очередь ожидающих потоков. Это может быть очень важно для обеспечения хорошего параллелизма, просто не в вашем тестовом коде, так как блокировка полностью не оспаривается. Остерегайтесь синтетических тестов, которые не аппроксимируют фактическое использование.