Последствия Lazy<T> и threadsafe false
Каковы последствия использования Lazy<T>
класс и маркировка isThreadSafe: false
во время инициализации?
В сценарии, где ленивый должен получить доступ к членам экземпляра, а не статическим членам, где ленивый инициализируется внутри конструктора класса, это автоматически требует isThreadSafe: false
во всех случаях?
2 ответа
В сценарии, где lazy требуется доступ к элементам экземпляра, а не к статическим элементам, где lazy инициализируется внутри конструктора класса, автоматически ли требуется isThreadSafe: false во всех случаях?
Нет - isThreadSafe
аргумент влияет только на то, как значение в пределах Lazy<T>
создано.
По сути, когда вы устанавливаете значение false, метод создания значения просто создает значение, устанавливает его во внутреннее хранилище и возвращает значение.
Если вы установите его в true, то создание будет обернуто внутри lock
, предотвращая создание объекта более чем одним потоком. Это соответствует LazyThreadSafetyMode.ExecutionAndPublication.
Вы также можете указать PublicationOnly
явно, что позволит создавать более одного значения, но затем использовать Interlocked.CompareExchange вместо блокировки, чтобы убедиться, что значение первой завершенной процедуры создания является тем, которое используется для объекта.
Обратите внимание, что ни один из этих параметров никак не влияет на то, какие члены используются для вычисления значения - они влияют только на то, как создается само значение. Доступ ко всему кроме создания всегда потокобезопасен. Если вы инициализируете Lazy<T>
член экземпляра в конструкторе класса, вы фактически гарантируете, что синхронизация не требуется, поэтому вы можете установить isThreadSafe
ложно - но это также означало бы, что нет абсолютно никакой причины использовать Lazy<T>
в этой ситуации, так как вы используете явную реализацию...
Из MSDN:
Немного
Lazy<T>
конструкторы имеютBoolean
названный параметрisThreadSafe
который используется, чтобы указать, является лиValue
свойство будет доступно из нескольких потоков. Если вы собираетесь получить доступ к свойству только из одного потока, передайтеfalse
получить скромный выигрыш в производительности. Если вы хотите получить доступ к свойству из нескольких потоков, передайтеtrue
поручитьLazy<T>
экземпляр для правильной обработки условий гонки, в которых один поток генерирует исключение во время инициализации.
Вы написали...
В сценарии, где lazy требуется доступ к элементам экземпляра, а не к статическим элементам, где lazy инициализируется внутри конструктора класса, автоматически ли требуется isThreadSafe: false во всех случаях?
Нет, это не имеет ничего общего с экземпляром против статического. Это связано с тем, будет ли лениво инициализированное значение получено в нескольких потоках или нет. Если к нему будут обращаться несколько потоков, используйте true
чтобы Lazy<T>
обрабатывает условия гонки для вас. Если не будет, используйте false
чтобы Lazy<T>
избегает взятия блокировки, которая даст вам очень небольшое, почти незаметное увеличение производительности (взятие неоспоримых блокировок ОЧЕНЬ быстро).