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. 关于Clipboard和GlobalAlloc函数的关系

    一句话:为了满足进程间通信,使用了clipboard的方法,clipboard是系统提供的一段任何进程都可以访问的公共内存块,malloc 和new分配的动态内存块是在进程的私有地址空间分配的,所以必 ...

  2. ntp 服务器

    ntp.sjtu.edu.cn 202.120.2.101 (上海交通大学网络中心NTP服务器地址)s1a.time.edu.cn 北京邮电大学s1b.time.edu.cn 清华大学s1c.time ...

  3. PythonNET网络编程2

    UDP应用:广播 广播:一点发送,多点接收 广播地址:一个网段内有一个指定的广播地址,是该网段的最大地址 192.168.2.255 广播风暴:一个网络中有大量的广播就会产生广播风暴占用大量带宽,影响 ...

  4. 【】queue

    [链接]点击打开链接 [题意] 实话实说,给 OIER 大神们排队这种工作是最让人头疼的事情了.因为同学们都有自尊 心,都不愿意排后面. 现在共有 n 个同学要排成一列,每个同学有两个属性:影响力和承 ...

  5. 洛谷——P2241 统计方形(数据加强版)

    https://www.luogu.org/problem/show?pid=2241 题目背景 1997年普及组第一题 题目描述 有一个n*m方格的棋盘,求其方格包含多少正方形.长方形 输入输出格式 ...

  6. JRebel热部署神器的配置(Eclipse,非教程,就自己看看)

    1.安装下载 直接下官方正版的就好了 eclipse->help->eclipse marketplace 搜索JRebel 然后按步骤一步步安好 安装好记得重启 2.注册 这东西在搞活动 ...

  7. linux中内存泄漏的检測(一)最简单的方法

    什么是内存泄漏 内存泄漏是指程序动态申请的内存在使用完后没有释放,导致这段内存不能被操作系统回收再利用. 比如这段程序,申请了4个字节的空间但没有释放,有4个字节的内存泄漏. #include < ...

  8. ScrollView ViewPager ListView三者共存的问题

    随喜结佛缘 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcWlueXVueWluZw==/font/5a6L5L2T/fontsize/400/fill/ ...

  9. Android中ImageView.ScaleType属性值

    1 android:scaleType="center" (1)当图片大于ImageView的宽高:以图片的中心点和ImageView的中心点为基准,按照图片的原大小居中显示,不缩 ...

  10. pstack.sh 改进版

    pstack.sh 改进版本 #!/bin/bash if (( $# < 1 )) ; then echo "usage: `basename $0` pid" 1> ...