1. Introduction
1. Delayed initialization occurs at NET 4.0, which is mainly used to improve performance, avoid wasting computing, and reduce program memory requirements. It can also be called on-demand loading.
2. Starting from net 4.0, C# began to support delayed initialization. Through the Lazy keyword, we can declare that an object is initialized only when it is used for the first time. If it has not been called, it will not be initialized, saving some unnecessary overhead and improving efficiency. At the same time, Lazy is inherently thread safe
3. Note: lazy < T > object initialization is thread safe by default. In a multithreaded environment, the first thread accessing the Value attribute of the lazy < T > object will initialize the lazy < T > object, and subsequent threads will use the data of the first initialization.
2. Application scenarios
- 1. Large and time consuming objects
Object creation is expensive and programs may not use it. For example, suppose that there is a Customer object with Orders attribute in memory, which contains a large number of Order objects. Initializing these objects requires a database connection. If the user never asks to display Orders or use the data in the calculation, it does not need to use system memory or calculation cycles to create it. By using lazy < Orders > to declare the Orders object for slow initialization, you can avoid wasting system resources when the object is not used. Object creation is expensive and you want to postpone its creation until other high-cost operations are completed. For example, suppose a program loads multiple object instances at startup, but only some of them need to be loaded immediately. The startup performance of the program can be improved by delaying the initialization of unnecessary objects until the required objects are created.
- 2. Packaging method
Save the delegate or method object and call it when needed.
Although you can write your own code to perform lazy initialization, we recommend using Lazy<T>. Lazy<T> And its related types also support thread safety and provide a consistent exception propagation strategy.
The following table lists NET Framework version 4 provides types that enable lazy initialization in different scenarios.
type | explain |
---|---|
Lazy<T> | A wrapper class that provides lazy initialization semantics for any class library or user-defined type. |
ThreadLocal<T> | be similar to Lazy<T> , except that the wrapper class provides lazy initialization semantics based on thread locality. Each thread can access its own unique value. |
LazyInitializer | Provide advanced static (Shared in Visual Basic) method for slow initialization of objects without paying the cost of classes. |
Lazy constructor
Lazy<T>() |
initialization Lazy<T> Class. When a lazy initialization occurs, a parameterless constructor of the target type is used. |
Lazy<T>(Boolean) |
initialization Lazy<T> Class. When lazy initialization occurs, the parameterless constructor of the target type and the specified initialization mode are used. |
Lazy<T>(Func<T>) |
initialization Lazy<T> Class. When slow initialization occurs, the specified initialization function is used. |
Lazy<T>(Func<T>, Boolean) |
initialization Lazy<T> Class. When delayed initialization occurs, the specified initialization function and initialization mode are used. |
Lazy<T>(Func<T>, LazyThreadSafetyMode) |
initialization Lazy<T> Class, which uses the specified initialization function and thread safe mode. |
Lazy<T>(LazyThreadSafetyMode) |
initialization Lazy<T> Class, which uses T's parameterless constructor and the specified thread safety mode. |
Lazy<T>(T) |
initialization Lazy<T> Class that uses a specified value that has been pre initialized. |
Lazy. Use of the value property
After a Lazy object is created, the corresponding object will not be created immediately. Once used Value, the corresponding variable will be instantiated, and the IsValueCreated attribute will become true.
The Value property is read-only, which means that if the Value stores a reference type, it cannot be assigned a new object. Only the public properties or fields of the object can be changed. If the Value stores a Value type, its Value cannot be modified. A new variable can only be created by calling the function of the variable again with a new parameter
After the Lazy object is created, before accessing the Value property of the variable for the first time,
Lazy. Use of isvaluecreated property
Judgment is instantiation
LazyThreadSafetyMode enumeration
appoint Lazy<T> Instance how to synchronize access between multiple threads.
All such constructors are fully thread safe. If locks are used internally, deadlocks may occur |
ExecutionAndPublication | ||
Not thread safe. | None | false | Not applicable. |
Fully thread safe; Thread contention for initialization value. | PublicationOnly |
The default initialization method is used when constructing
using System; namespace LazyUsage { class LazyDemo { static void Main() { Lazy<Data> lazyData = new Lazy<Data>(); Console.WriteLine("Main->is lazyData Initialized? value = " + lazyData.IsValueCreated); lazyData.Value.Print();//Only when accessed here Data Real initialization Console.WriteLine("Main->is lazyData Initialized? value = " + lazyData.IsValueCreated); Console.ReadKey(); } } class Data { public Data() { Console.WriteLine("Data::.ctor->Initialized"); } public void Print() { Console.WriteLine("Data::Print->println"); } } }
Output results
Main->is lazyData Initialized? value = False
Data::.ctor->Initialized
Data::Print->println
Main->is lazyData Initialized? value = True
Class with the specified delegate when constructing
using System; namespace LazyUsage { class LazyDemo { static void Main() { //Specifies the delegate to initialize Data Lazy<Data> lazyData = new Lazy<Data>( () => { Console.WriteLine("Main->lazyData will be Initialized!"); return new Data("Test"); }); Console.WriteLine("Main->is lazyData Initialized? value = " + lazyData.IsValueCreated); lazyData.Value.Print(); Console.WriteLine("Main->is lazyData Initialized? value = " + lazyData.IsValueCreated); Console.ReadKey(); } } class Data { public string Name { get; private set; } public Data(string name) { Name = name; Console.WriteLine("Data::.ctor->Initialized,name = "+name); } public void Print() { Console.WriteLine("Data::Print->name = " + Name); } } }
Output results
Main->is lazyData Initialized? value = False Main->lazyData will be Initialized! Data::.ctor->Initialized,name = Test Data::Print->name = Test Main->is lazyData Initialized? value = True
Expansion Implementation delay attribute
class Customer { private Lazy<Orders> _orders; public string CustomerID {get; private set;} public Customer(string id) { CustomerID = id; _orders = new Lazy<Orders>(() => { return new Orders(this.CustomerID); }); } public Orders MyOrders { get { return _orders.Value; } } }
ThreadLocal < T > class
This class is equivalent to a thread boundary, which limits the value and function of variables to threads. So the types wrapped in this class are thread safe. The wrapped type variables of this class can only be used in this thread. Other threads, including child threads, cannot use them.
Constructor
ThreadLocal<T>() |
initialization ThreadLocal<T> example. |
ThreadLocal<T>(Boolean) |
initialization ThreadLocal<T> Instance and specify whether all values can be accessed from any thread. |
ThreadLocal<T>(Func<T>) |
Class using the specified valueFactory function ThreadLocal<T> example. |
ThreadLocal<T>(Func<T>, Boolean) |
Class with the specified valueFactory function and a flag indicating whether all values can be accessed from any thread ThreadLocal<T> example. |
attribute
IsValueCreated |
Gets whether to initialize on the current thread Value. |
Value |
Gets or sets the value of this instance of the current thread. |
Values |
Gets a list of all values currently stored by all threads that have accessed this instance. |
Provides local storage of thread data.
static void Main(string[] args) { ThreadLocal<int> threadLocal = new ThreadLocal<int>(); //In the main thread, the value of this variable is 1 threadLocal.Value = 1; new Thread(() => Console.WriteLine($"managed thread ID: {Thread.CurrentThread.ManagedThreadId} The value is:{threadLocal.Value++}")).Start(); new Thread(() => Console.WriteLine($"managed thread ID: {Thread.CurrentThread.ManagedThreadId} The value is:{threadLocal.Value++}")).Start(); new Thread(() => Console.WriteLine($"managed thread ID: {Thread.CurrentThread.ManagedThreadId} The value is:{threadLocal.Value++}")).Start(); Console.WriteLine($"Main thread ID: {Thread.CurrentThread.ManagedThreadId} The value is:{threadLocal.Value}"); }
Output results:
Managed thread ID: 10 value: 0
Main thread ID: 1 Value: 1
Managed thread ID: 11 value: 0
Managed thread ID: 12 value: 0
using System; using System.Threading; using System.Threading.Tasks; class ThreadLocalDemo { // Demonstrates: // ThreadLocal(T) constructor // ThreadLocal(T).Value // One usage of ThreadLocal(T) static void Main() { // Thread-Local variable that yields a name for a thread ThreadLocal<string> ThreadName = new ThreadLocal<string>(() => { return "Thread" + Thread.CurrentThread.ManagedThreadId; }); // Action that prints out ThreadName for the current thread Action action = () => { // If ThreadName.IsValueCreated is true, it means that we are not the // first action to run on this thread. bool repeat = ThreadName.IsValueCreated; Console.WriteLine("ThreadName = {0} {1}", ThreadName.Value, repeat ? "(repeat)" : ""); }; // Launch eight of them. On 4 cores or less, you should see some repeat ThreadNames Parallel.Invoke(action, action, action, action, action, action, action, action); // Dispose when you are done ThreadName.Dispose(); } } // This multithreading example can produce different outputs for each 'action' invocation and will vary with each run. // Therefore, the example output will resemble but may not exactly match the following output (from a 4 core processor): // ThreadName = Thread5 // ThreadName = Thread6 // ThreadName = Thread4 // ThreadName = Thread6 (repeat) // ThreadName = Thread1 // ThreadName = Thread4 (repeat) // ThreadName = Thread7 // ThreadName = Thread5 (repeat)