1. 概述

我们创建某一个对象需要很大的消耗,而这个对象在运行过程中又不一定用到,为了避免每次运行都创建该对象,这时候延迟初始化(也叫延迟实例化)就出场了。

延迟初始化出现于.NET 4.0,主要用于提高性能,避免浪费计算,并减少程序内存要求。也可以称为,按需加载。

2. 基本语法

Lazy<T> xx = new Lazy<T>();//xx代表变量名

3. 举例实现

首先创建一个Student类,代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace LazyTest
{
class Student
{
public Student()
{
this.Name = "DefaultName";
Console.WriteLine("调用Student的构造函数");
} public string Name { get; set; }
}
}

创建一个控制台程序,代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace LazyTest
{
class Program
{
static void Main(string[] args)
{
Lazy<Student> student = new Lazy<Student>();
if (!student.IsValueCreated)
{
Console.WriteLine("Student未初始化");
}
Console.WriteLine(student.Value.Name);
if (student.IsValueCreated)
{
Console.WriteLine("Student已经初始化");
}
Console.ReadKey();
}
}
}

设置断点调试后发现,在new完之后,student的IsValueCreated的值是false,value的值是null

接着往下走,调用到Name属性时,student的IsValueCreated的值是true,value的值已经不为null了

运行结果:

结果可以看出,Student是在输出Name属性才进行初始化的,也就是在第一次使用时才会去初始化,这样就可以达到减少消耗的目的。

这个例子很简单,也是Lazy<T>最基本的使用方式。我们还可以使用 Lazy<T> 的重载函数 Lazy<T> (Func<T>) 传入一个带返回值的委托来设置延迟初始化对象的属性值。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace LazyTest
{
class Program
{
static void Main(string[] args)
{
Lazy<Student> student = new Lazy<Student>(() => new Student { Name = "SetName" });
if (!student.IsValueCreated)
{
Console.WriteLine("Student未初始化");
}
Console.WriteLine(student.Value.Name);
if (student.IsValueCreated)
{
Console.WriteLine("Student已经初始化");
}
Console.ReadKey();
}
}
}

运行结果:

注:Lazy<T> 对象初始化默认是线程安全的,在多线程环境下,第一个访问 Lazy<T> 对象的 Value 属性的线程将初始化 Lazy<T> 对象,以后访问的线程都将使用第一次初始化的数据。

4. 自我分析

Lazy实现的原理应该是简单的,只是单独做了一个封装的类而已,下面是我们自我猜测的主要源码:

 public class MyLazy<T> where T : new()
{
private static object _lock = new object(); private bool _isValueCreated = false; private T _value = default(T);
public bool IsValueCreated
{
get
{
return _isValueCreated;
}
} public T Value
{
get
{
_isValueCreated = true;
Monitor.Enter(_lock);
if (_value==null)
{
_value = new T();
}
Monitor.Exit(_lock);
return _value;
}
} }

测试:

 public class People
{
public People()
{
Console.WriteLine("被构造了");
}
public string Name { get; set; }
}
 public static class Test
{
static void Main()
{
MyLazy<People> lazy = new MyLazy<People>();
Console.WriteLine(lazy.IsValueCreated); //False
var p = lazy.Value.Name; //被构造了
Console.WriteLine(lazy.IsValueCreated); //True
Console.ReadKey();
}
}

当然了,这只是最简单的一种情况,然后我想到了源码中应该还会考虑到 类的单例,私有构造的各种情况。然后我用人家微软封装好的 Lazy做个测试吧。哎呀,官方的这咋还报错呢!

 public static class Test
{
static void Main()
{
Lazy<People> lazy = new Lazy<People>(); var te = lazy.Value.Name;
Console.ReadKey();
}
}
public class People
{
private People()
{
Console.WriteLine("被构造了");
}
public string Name { get; set; }
}

结果:

那我去看看Lazy的源码,找吐槽点了

5. 应用场景

有一个对象的创建开销很大,而程序可能不会使用它。例如,假定您的程序在启动时加载若干个对象实例,但只有一些对象实例需要立即执行。通过将不必要的对象的初始化延迟到已创建必要的对象之后,可以提高程序的启动性能。

参考文献:https://blog.csdn.net/yinghuolsx/article/details/73824220

C#性能优化:延迟初始化Lazy的更多相关文章

  1. 不要使用 Dispatcher.Invoke,因为它可能在你的延迟初始化 Lazy 中导致死锁

    WPF 中为了 UI 的跨线程访问,提供了 Dispatcher 线程模型.其 Invoke 方法,无论在哪个线程调用,都可以让传入的方法回到 UI 线程. 然而,如果你在 Lazy 上下文中使用了 ...

  2. C#性能优化:延迟初始化Lazy<T>

    1. 概述 我们创建某一个对象需要很大的消耗,而这个对象在运行过程中又不一定用到,为了避免每次运行都创建该对象,这时候延迟初始化(也叫延迟实例化)就出场了. 延迟初始化出现于.NET 4.0,主要用于 ...

  3. 延迟初始化Lazy

    延迟初始化出现于.NET 4.0,主要用于提高性能,避免浪费计算,并减少程序内存要求.也可以称为,按需加载. 基本语法: Lazy<T> xx = new Lazy<T>(); ...

  4. C#延迟初始化Lazy<T>

    1. 概述 我们创建某一个对象需要很大的消耗,而这个对象在运行过程中又不一定用到,为了避免每次运行都创建该对象,这时候延迟初始化(也叫延迟实例化)就出场了. 延迟初始化出现于.NET 4.0,主要用于 ...

  5. C# 延迟初始化 Lazy<T>

    概念:延时初始化重点是延时,用时加载,意思是对象在使用的时候创建而不是在实例化的的时候才创建.   延时加载主要应用的场景: 数据层(ADO.NET或Entity Framework等ORM,Java ...

  6. 关于Hibernate性能优化之 FetchType=Lazy时查询数据

    当表A和表B一对多的关系 对于A和B的实体类,设置FetchType=EAGER时,取A表数据,对应B表的数据都会跟着一起加载,优点不用进行二次查询.缺点是严重影响数据查询的访问时间. 解决办法Fet ...

  7. C#性能优化之Lazy<T> 实现延迟初始化

    在.NET4.0中,可以使用Lazy<T> 来实现对象的延迟初始化,从而优化系统的性能.延迟初始化就是将对象的初始化延迟到第一次使用该对象时.延迟初始化是我们在写程序时经常会遇到的情形,例 ...

  8. Python中__get__, __getattr__, __getattribute__的区别及延迟初始化

    本节知识点 1.__get__, __getattr__, __getattribute__的区别 2.__getattr__巧妙应用 3.延迟初始化(lazy property) 1.__get__ ...

  9. Java - 延迟初始化

    延迟初始化(lazy initialization),也就是在真正被使用的时候才开始初始化的技巧. 不论是静态还是实例,都可以进行延迟初始化. 其本质是初始化开销和访问开销之间的权衡. 毕竟是一种优化 ...

随机推荐

  1. Codeforces Round #445 Div. 1 C Maximum Element (dp + 组合数学)

    题目链接: http://codeforces.com/contest/889/problem/C 题意: 给你 \(n\)和 \(k\). 让你找一种全排列长度为\(n\)的 \(p\),满足存在下 ...

  2. SpringBoot 使用yml配置 mybatis+pagehelper+druid+freemarker实例

    SpringBoot 使用yml配置 mybatis+pagehelper+druid+freemarker实例 这是一个简单的SpringBoot整合实例 这里是项目的结构目录 首先是pom.xml ...

  3. docker 第一课 —— 从容器到 docker

    1. 容器的概念 一种虚拟化的解决方案 与虚拟机所不同的是,虚拟机通过中间层,将一台或多台独立的机器虚拟运行于物理硬件之上: 而容器是直接运行于操作系统内核之上的用户空间: 基于上述,容器虚拟化也被称 ...

  4. ssi的使用 开启 配置等

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/lsfhack/article/details/69664402ssi的定义SSI(Server Si ...

  5. 10.9 android输入系统_APP跟输入系统建立联系和Dispatcher线程_分发dispatch

    12. 输入系统_APP跟输入系统建立联系_InputChannel和Connection核心: socketpair // 第9课第3节_输入系统_必备Linux编程知识_任意进程双向通信(scok ...

  6. POS 60域用法

    版权声明:本文为博主原创文章,未经博主允许不得转载. 自定义域(Reserved Private) 1.变量属性 N...17(LLLVAR),3个字节的长度值+最大17个字节的数字字符域. 压缩时用 ...

  7. 【例题 6-3 UVA - 442】Matrix Chain Multiplication

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 用栈来处理一下表达式就好. 因为括号是一定匹配的.所以简单很多. ab x bc会做abc次乘法. [代码] #include< ...

  8. APK瘦身记,怎样实现高达53%的压缩效果

    作者:非戈@阿里移动安全,很多其它技术干货.请訪问阿里聚安全博客 1.我是怎么思考这件事情的 APK是Android系统安装包的文件格式.关于这个话题事实上是一个老生常谈的题目.不论是公司内部.还是外 ...

  9. OpenExeConfiguration的使用

    //应用程序的路径 string appPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "App.exe"); ...

  10. 魔兽争霸war3心得体会(一):UD的冰甲蜘蛛流

    玩war3好几年了,之前都是打打电脑,随便玩玩的.刚刚在浩方等平台上和人玩的时候,各种被虐,很难赢一局.从去年开始,才认真玩.思考下各种战术. 最初,使用的是兽族orc,后来觉得兽族不够厉害,玩到对战 ...