Сколько стоит ключевое слово volatile в многопроцессорной системе?
-
05-07-2019 - |
Вопрос
мы сталкиваемся с проблемами производительности, и один потенциальный виновник - это централизованное использование изменчивого синглтона. конкретный код имеет вид
class foo {
static volatile instance;
static object l = new object();
public static foo Instance {
if (instance == null)
lock(l) {
if (instance == null)
instance = new foo();
}
return foo();
}
}
это работает на 8-сторонней машине, и мы наблюдаем переключение контекста на скорость 500 000 в секунду. типичные системные ресурсы хороши - загрузка процессора 25%, загрузка памяти 25%, низкий уровень ввода-вывода, отсутствие подкачки и т. д.
вызывает ли использование изменчивого поля барьер памяти или какую-либо перезагрузку кеша процессора? или он просто идет за основной памятью каждый раз, только для этого поля?
Решение
lock
действительно создает барьер памяти, поэтому, если вы всегда обращаетесь к экземпляру в блокировке, вам не нужно энергозависимое.
Согласно этому сайт :
Ключевое слово C # volatile реализует семантику получения и выпуска, которая подразумевает барьер чтения памяти при чтении и барьер памяти записи при записи.
Другие советы
volatile не будет вызывать переключение контекста. Если вы видите 500 000 переключений контекста в секунду, это означает, что ваши потоки блокируют что-то, а volatile является не виновником.
К сожалению, синглтон получает плохой рэп практически за все :)
Это не моя область знаний, но, насколько я знаю, в volatile нет ничего особенного, кроме того, что компилятор / среда выполнения НЕ переупорядочивает чтение / запись (в переменную) в целях оптимизации.
Редактировать: я исправлен. Изменчивость не только создает барьеры памяти, но и то, что происходит (и, между прочим, производительность), во многом зависит от конкретного процессора. См. http://dotnetframeworkplanet.blogspot.com /2008/11/volatile-field-and-memory-barrier-look.html р>
Вот почему вам все еще нужен замок.
Вопросы, на которые, возможно, не ответили уже:
<Ол>В нашем примере volatile не должно быть предметом какого-либо "замедления". Однако lock () может включать в себя огромные обходы ядра, особенно если за блокировку много споров.
В этом случае нет необходимости блокировать ваш синглтон, вы можете просто делать
class Foo {
static Foo instance = new Foo();
public static Foo FooInstance() {
return instance ;
}
}
Конечно, если 'instance' используется во многих разных потоках, вам все равно придется блокировать () все, что изменяет этот Foo, если только все методы / свойства Foo не доступны только для чтения. например.
class Foo {
static Foo instance = new Foo();
object l = new object();
int doesntChange = 42;
int canChange = 123;
public static Foo FooInstance() {
return instance ;
}
public void Update(int newVal) {
lock(l) { // you'll get a lot of trouble without this lock if several threads accesses the same FOO. Atleast if they later on read that variable
canChange = newVal;
}
public int GetFixedVal() {
return doesntChange; //no need for a lock. the doesntChange is effectivly read only
}
}
Нет необходимости использовать volatile для синглтона, так как вы устанавливаете его ровно один раз - и блокируете код, который его устанавливает. См. статью Джона Скита о синглетонах для получения дополнительной информации.
Короткий ответ: да, он создает барьер памяти (сбрасывает все и уходит в основную память, а не только в эту переменную), но нет, это не будет причиной переключения контекста.
Кроме того, как уже упоминали другие, я не считаю, что здесь необходима изменчивость.