Дневник сертифицированного .NET разработчика. Заметки, советы, новости из мира .NET и C#.
Для связи: @SBenzenko
Поддержать канал:
- https://boosty.to/netdeveloperdiary
- https://patreon.com/user?u=52551826
- https://pay.cloudtips.ru/p/70df3b3b
Post #2965
2.85K
День 2464. #ЗаметкиНаПолях
Потокобезопасная Инициализация с Помощью LazyInitializer
Хотя Lazy<T> является основным решением для ленивой инициализации в .NET, существует менее известная альтернатива, которая может быть более эффективной в некоторых сценариях: LazyInitializer.EnsureInitialized.
Этот статический метод обеспечивает потокобезопасную инициализацию с рядом ключевых характеристик:
- Только ссылочные типы: работает только с классами, но не со значениями.
- Обнаружение на основе NULL: использует значение NULL для определения необходимости инициализации.
- Эффективное использование памяти по сравнению с System.Lazy<T>: не требуется дополнительный объект-обёртка.
Метод предлагает несколько перегрузок для различных сценариев:
Замечания по потокобезопасности
По умолчанию LazyInitializer.EnsureInitialized ведёт себя как LazyThreadSafetyMode.PublicationOnly:
Несколько потоков могут создавать экземпляры одновременно. Сохраняется только первое успешное назначение. Остальные экземпляры отбрасываются.
Для строгой потокобезопасности используйте перегрузку с блокировкой синхронизации, чтобы гарантировать, что фабричный метод будет выполнен только один раз.
Внутренняя реализация этого аналогична следующему коду:
Преимущества
Главное преимущество перед Lazy<T> — вместо хранения объекта-обёртки Lazy<T> вы напрямую используете целевой экземпляр. Также это снижает затраты памяти, экономя одно поле на каждое лениво инициализированное значение.
Источник: https://www.meziantou.net/thread-safe-initialization-with-lazyinitializer.htm
Потокобезопасная Инициализация с Помощью LazyInitializer
Хотя Lazy<T> является основным решением для ленивой инициализации в .NET, существует менее известная альтернатива, которая может быть более эффективной в некоторых сценариях: LazyInitializer.EnsureInitialized.
Этот статический метод обеспечивает потокобезопасную инициализацию с рядом ключевых характеристик:
- Только ссылочные типы: работает только с классами, но не со значениями.
- Обнаружение на основе NULL: использует значение NULL для определения необходимости инициализации.
- Эффективное использование памяти по сравнению с System.Lazy<T>: не требуется дополнительный объект-обёртка.
Метод предлагает несколько перегрузок для различных сценариев:
Sample? _instance = null;
// Инициализация через конструктор по умолчанию
var instance =
LazyInitializer.EnsureInitialized(ref _instance);
// Фабричный метод
var instance =
LazyInitializer.EnsureInitialized(
ref _instance,
() => new Sample()
);
// Фабричный метод вызывается 1 раз, даже если нескольким потокам требуется инициализация
var syncLock = new object();
var instance =
LazyInitializer.EnsureInitialized(
ref _instance,
ref syncLock,
() => new Sample()
);
Замечания по потокобезопасности
По умолчанию LazyInitializer.EnsureInitialized ведёт себя как LazyThreadSafetyMode.PublicationOnly:
Несколько потоков могут создавать экземпляры одновременно. Сохраняется только первое успешное назначение. Остальные экземпляры отбрасываются.
Для строгой потокобезопасности используйте перегрузку с блокировкой синхронизации, чтобы гарантировать, что фабричный метод будет выполнен только один раз.
Внутренняя реализация этого аналогична следующему коду:
var instance = Volatile.Read(ref _instance) ??
Interlocked.CompareExchange(
ref _instance,
new Sample(),
null);
Преимущества
Главное преимущество перед Lazy<T> — вместо хранения объекта-обёртки Lazy<T> вы напрямую используете целевой экземпляр. Также это снижает затраты памяти, экономя одно поле на каждое лениво инициализированное значение.
Источник: https://www.meziantou.net/thread-safe-initialization-with-lazyinitializer.htm
- 👍 15
