Является ли изменчивая переменная "читается" так же быстро, как обычно?

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

Могут ли переменные volatile помещаться в кеш процессора или всегда извлекаются из основной памяти?

Ответ 1

Вы действительно должны проверить эту статью: http://brooker.co.za/blog/2012/09/10/volatile.html. В статье в блоге утверждается, что волатильные чтения могут быть намного медленнее (также для x86), чем нестабильные чтения на x86.

  • Тест 1 является параллельным чтением и записью в нелетучую переменную. Там нет механизма видимости, и результаты чтения потенциально устаревший.
  • Тест 2 - это параллельное чтение и запись в изменчивую переменную. Это не относится конкретно к вопросу ОП. Однако стоит отметить, что соперничающая летучесть может быть очень медленной.
  • Тест 3 - это считывание в летучее в узком цикле. Продемонстрировано, что семантика того, что значит быть изменчивым, указывает на то, что значение может меняться с каждой итерацией цикла. Таким образом, JVM не может оптимизировать чтение и вытащить его из цикла. В тесте 1, вероятно, значение было прочитано и сохранено один раз, поэтому фактическое "чтение" не происходит.

Тесты Марка Букера

Кредит Марку Букеру за выполнение этих тестов.

Ответ 2

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

JMM cookbook от Doug Lea, см. таблицу архитектуры внизу.

Чтобы уточнить: никаких дополнительных накладных расходов, связанных с самим чтением, нет. Для обеспечения правильного упорядочения используются барьеры памяти. JSR-133 классифицирует четыре барьера "LoadLoad, LoadStore, StoreLoad и StoreStore". В зависимости от архитектуры некоторые из этих барьеров соответствуют "нет-op", что означает, что никаких действий не предпринимается, другие требуют ограждения. Существует неявная стоимость, связанная с самой загрузкой, хотя может быть понесена, если забор находится на месте. В случае x86 только бар StoreLoad приводит к заграждению.

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

Летучие - это не то, что нужно использовать с блеском, но этого также не следует опасаться. Есть много случаев, когда волатильность будет достаточной для более тяжелой фиксации.

Ответ 3

Неустойчивые чтения не могут быть такими быстрыми, особенно для многоядерных процессоров (но и только одноядерных). Исходное ядро ​​должно извлекать из фактического адреса памяти, чтобы убедиться, что оно получает текущее значение - эта переменная действительно не может быть кэширована.

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

Ответ 4

Это зависит от архитектуры. То, что volatile делает, говорит компилятору не оптимизировать эту переменную. Это заставляет большинство операций обрабатывать переменное состояние как неизвестное. Поскольку он изменчив, он может быть изменен другим потоком или другой аппаратной операцией. Таким образом, чтение должно будет перечитать переменную, и операции будут иметь вид read-modify-write.

Эта переменная используется для драйверов устройств, а также для синхронизации с мьютексами/семафорами в памяти.

Ответ 5

volatile подразумевает, что компилятор не может оптимизировать переменную, поместив ее значение в регистр CPU. Он должен быть доступен из основной памяти. Однако он может быть помещен в кеш процессора. Кэш гарантирует согласованность между любыми другими CPU/ядрами в системе. Если память сопоставлена ​​с IO, тогда ситуация немного сложнее. Если он был разработан как таковой, аппаратное обеспечение предотвратит кэширование адресного пространства, и все обращения к этой памяти перейдут на аппаратное обеспечение. Если такой конструкции нет, разработчикам оборудования могут потребоваться дополнительные инструкции по процессору, чтобы обеспечить чтение/запись через кеши и т.д.

Как правило, ключевое слово "volatile" используется только для драйверов устройств в операционных системах.