00:00
来看一个,我们看一个概念叫惰性函数,什么叫惰性函数呢?听其名而知其首先它是一个函数。第二个它是一个惰性函数,诶为什么要有惰性函数呢?我举一个例子,我先给大家看一个应用的场景,我看应用场景同学们你们都很知道啊,你们清楚将来你们做这个大数据处理。有没有一种这样的可能性,就是你要处理很多很多数据。但是。有可能你处理完了过后用户不用。打个比方,在最早的时候,这个所有的这个门户网站是怎么加载首页面的呢?在最早的时候,比如像您像这个阿贾克斯这个技术还没有出现的时候,比如阿贾克斯应该是06年07年在整个国内兴起,但是在零这之前呢,所有的门户网站是怎么加载的呢?是打开首页面。打开首页面,它把整个页面全部加载。
01:03
大家知道一个一个首页面的内容很多,但实际上我们的用户很奇怪,他打开首页面以后,他可能就看了一屏,诶就走了,那可能你的首页里面可能有个五瓶,有五瓶有六屏,结果你后面加载的就浪费了。诶,所以说这种场景在我们大数据计算里面也有可能是出现的,什么意思呢?大家看我这里写了这么几个地方,这个地方就出现一个叫惰性计算的一种优化什么呢?它尽可能的延迟表达式的求值。哎,你比如说,比如说这个延可能延迟表达式就是是许多函数式编程语言的特性惰性集合,在需要时提供其他元素,无需预先计算它们,那这样就带来一些好处了,什么呢?首先你可以将耗时的计算推迟到绝对需要时再去计算。
02:02
你你比如说在同学们学,呃,有些同学学过像这个habit对吧,学habit的时候呢,它就有一个叫做延时加载的东西。它是是,它是需要你在进行页面渲染的时候,诶,他才真正帮你查询,这个才真正到数据库查询,其实这个就就类似于到推迟到绝对需要时才计算,那么这样你就可以创造无限多个集合,只要他们继续接收请求,就会继续提供元素函数的惰性,能够能够得到更高效的代码,Java。有没有惰性呢?Java没有惰性,没有提供惰性的原生支持,但实勘了直接提供了,这个就叫。惰性函数,那这样讲可能同学们还是不清晰,我这里准备了一个图,叫大数据推荐系统,大数据推荐系统我给大家看一个小案例啊,我给大家看一个小案例,哎,比如说。
03:02
啊,我给同学们看一个小案例啊,我给大家看一个小案例在哪里呢?好,我这里有一个小东西,我看看还在不在啊。我看看还在不在,我曾经发了个邮件。哦,这里。好,大家先简单看一下这个。呃。这这个地方有一个大数据的一个推荐,我这个这个往往下走啊,这这这这么慢,这个好我往下面走一下。这儿有一个图。这个图好,我再往下面走一下就到了。哦,这儿走走了啊,到这儿来了。有一个,诶,这怎么还没到啊,往下再走一下。好,往下再走一下。
04:00
好,就这个图,就这个图。就这个图。大家看大数据,你们在学习的时候呢,老师应该画过这个大数据的生态体系图,画过这个同学们还有没有印象,就是说老师在讲大数据的时候呢,说明我们大数据这个技术生产体系,它主要完成了最主要的核心功能,就是完成三个功能,一个就是对数据的采集。就数据量很大,我怎么采集,像卡夫卡就是在这里出现的,还有一个呢,就是对大数据的存储。对,还有一个就是对大数据的计算,其实大数据主要解决这么三个问题,那这里有个最麻烦的事情是什么呢?同学们。当我们采集到很多很多数据的时候,你是不是要马上计算的问题,这就很麻烦了,因为我们如果说把这个数据马上计算出来,我们计算完了过后,把它放到这个业务层了,比如说我们入库了,或者是呃落盘了,但是别人不用。
05:03
那你不这个事,事情不就白干了吗?所以说这里面就出现一个什么呢,我们在这个计算和这个存储之间能不能做一个缓冲。能不能做一个缓冲的问题,其实说白了就是我们先把数据存到这个地方,存到地方,如果你真的要计算,我再调用我的Spark进行实时计算,最后把这个结果用Java意义的技术展现给我们的用户,诶,这个呢就是一个优化。其实就是句画好,你看我这个图一下子大家就清晰了,好我用这个一点东西呢,大家就有点感觉了,大家看我把这个图打开给弄一,你看这样子的。说我们现在呢有一个京东,京东呢准备做一个推荐系统。那么我们这有很多用户,这个用户在网上,在京东网站上买了很多的产品,买了很多产品就形成日志了,那么日志有了过后呢,我们用相应的技术进行采集,采集完了过后呢,按理说采集完了过后就会发给我们的这个Spark进行一个实时计算,然后把这个结果呢,推给我们Java e,最后入库或者是到文件,最后用Java技术提供给我们的用户,就看到相应的推荐的产品了,比如说我们买了一个善存片,或者买了一一件衣服一或者是一双鞋子,那么当你买完过后呢,它的下面就会展现出你还可以购买其他的产品。
06:29
但这种应用是实时的,这种大数据呢也这样也很对,但是有些应用场景你这样做呢,就不合理了。因为这个数据量会非常大。诶,那怎么办呢?我们可以先把它缓冲到这个地方去,等到用户真的要用其中一个结果时,我们马上调用去进行计算,好,这个就是惰性函数的一个由来,那么我们看看惰性函数到底是怎么来实现的呢?来看案例。好,首先我们看Java怎么实现的,Java没有原生态的这种懒加载机制,它一般是通过什么呢?一个自己的函数来实现,比如说同学们学Java的时候,一定学过单例模式的懒汉式懒汉,还有一个叫二汉。
07:18
懒汉式是怎么实现的呢?核心代码大致就是这个意思,当我们去加载一个类的时候,这个类并没有去真正的构建你的这个单例对象。当我调用的时候,比如我调用get properties,如果它为空,我才去初始化我的对象,对吧?诶,这个其实就是它核心的源代码。那么这是Java要自己去实现懒加载,那么到了我们时看了好同学们简单了。SC呢,非常的简单,这样做的。当函数返回值被声明为lazy就懒的意思是函数的执行将会被推迟,直到我们首次取或者是用这个返回值,该函数才会才会真正的执行,我们将这个函数称之为惰性函数。
08:10
在Java呢,将这些框架代码称之为懒加载。好,同学们,我们来看一个小小的案例,那为了省事,我这个案例已经准备好了。代码都很简单哈。来吧,同学们,我们。新建一个小包,我们新建一个包叫做lazy。好的,Daisy。同学们。好,我写一个DEMO,好吧,写个DEMO叫lazy DEMO。L。ZYDEMOOK,那么现在呢,我们写一个object,我把代码呢,给大家拿过来啊,代码都很简单,没有难度的,呃,我看这地方是不是哪个地方写错了,哦哦呃,我看看哦,这个地方这方少了少少了一个换行哈,好,这样子就OK了。啊,这样就OK了,那么我们来简单看一下代码是什么意思,同学们看。
09:03
嗯,这个地方是一个上函数。这个函数干什么呢?它返回呃,一个和,那么这地方我输出了一句话,大家看到没有,我为了证明这个函数有没有执行,我输出一句话。一句话OK,好,同学们,现在呢,我先把这句话拿掉,我们先看一下,在这里我调用了上传入了十和20,然后呢,这边有个结果,但是我在前面加了一个类与与,如果说我这地方不做任何的处理,那么这个上函数一定会被执行,看一下走。我们先运行一下,同学们可以看到呢,这个时候。哦,同样道理,又是个lazy,又又又是个关键字啊,来,重新构建一下就行了。换,换一个叫my lazy就行。啊,每次价格卖就行了。好,我们再跑一下,同学们跑的时候呢,你会看到它会正常的输出上被执行的完全正确,他先执行这个,再执行这个,这这个print very easy啊,就说明它是实时的进行这个调用函数的,现在我改变了,我希望它实现一个懒加载。
10:18
当我再加了个lazy过后呢?我们来看看情况会发生什么样的变化呢?好,我们发现很有意思,函数居然没有被调用。没有被调用。他们并没有输出这个上。那说明它其实只是加了一个引用,就是它可能有个缓存缓缓冲层,在这个缓冲层里面呢,它预先加载了这一个,这个十和20,这个数和十和20,你不需要再加了它,它已经保留在它的缓存层了,可能他做了一个队列。然后呢,这个队列引用到我们函数,只是没有执行,因为将来我们这个执行的任务可能很费时间,说老师这个不费时间,不就N1加N2吗?啊,我你要这么理解,这课就没法讲了啊,老师你这动不动就比N1加N2不费时间,你将来可能是一个很复杂计算嘛,对吧,可能是个大数据的排序,可能是一个统计一篇文章的一个,呃,文章有多少个单词等等等等,你就说这只是一个简单的例子嘛,好,他只是把它加载的一个缓冲层。
11:21
诶,可能做了一个队列说,诶等待计算,这是没有真正预算,他可能有个优先级啊,排排排到这个队列里面去,等到我要用的时候,把那个拎出来提到前面去进行进行运算,诶这个就很好了,那怎么办呢?我现在就让他用。哎,这个时候我们就真正用到这个RS了,诶。在用R11前才会执行,那么我们来看当我要用的时候,它会这个这个执行顺序会怎么样呢?首先我们来看看这个结果啊,首先告诉大家,它仍然是先输出它。也就是说在这句话并没有调用,他把这个输出来过后,到了你用的时候,他才去执行,最后把这个结果返回看输出的顺序。
12:04
好,同学们可以看到这里面的代码。诶,你看顺序跟我们想的是一样的,呃,这句话仍然没有导致函数的调用,它输出了这个杠杠,等到你这真的要用了啊,那真的要用的时候,他发现R是已经被引用了,他就可能从你这个整个你这个缓冲里面,这个队列里边啊,或者是个反正肯定是个数据结构,他就把这个拎出来,真正式的加入可能有比如说这个是缓冲队列,还有一个真正的是执行队列。啊,然后呢,他把这个东西给你加载到一个执行队列上,就开始执行了。那这样子呢?这个结果你看就先执行再输出结果啊,这就是一种懒加载的经典应用啊,经典应用好也很简单也很简单,好这是我们惰性函数的一个使用,那么我们来看看惰性函数还有什么注意事项吗?第一个lazy不能够修饰VAR变量。
13:03
这说明它在进行预加载的时候,你这个变量就已经不能变了,它其实已经把它固定了,说它是线程安全的,它现场安全的,所以你不能用VAR来修饰这个变量,也就是说你不能把它写成。这个。你写成这个的吗?直接报错,他说什么呀,看这个下面提示,他说lazy Mo DeFine or no only with value形式就是只能修饰这种VR的,呃,V的啊,所以说你这个不能改,这是第一个细节。这是第一个细节。第二个细节需要知道是,不但在调用函数时加lazy会导致函数的延迟执行。我们在声明一个变量时,如果给它加了LA,那么这个变量值的分配也会被推迟。我举个例子。啊呃,这些都不难哈,就是告诉大家。Scanner,走。好,你,你们来看我写一个小案例,Va。
14:01
啊v number1等于十一百一千回错,你看马上就分配了,马上就分配了,我们再写一段代码lazy。Value number2。比如说这个呢,是88回车,诶同学们可以看到这个NUMBER2并没有复制,他说我要用lazy进进这个这这个处理,现在这个在这个时候,其实NUMBER2并没有得得到真正的分配。它其实也是一个预先处理,那现在呢,我们再去用它的时候,就用到了比较NUMBER2回车。诶,这个时候就真正分配了,好所以说大家注意这个细节就行了,不不难啊不难,好,那关于这个呃,惰性函数呢,我们就先给大家讲到这个地方,其实呃东西很简单,只是同学们要知道什么时候用。我我再多说一句啊,将来大家在经营大数据,计算出什么作用呢?
15:00
就是呃,根据你的业务逻辑,根据业务逻辑你你希望你有大量的这个计算,但是呢,这个计算你根据你的业务逻辑判断,可能并不是实时马上就要把这个结果给他推过去。而是在第,而是在用户使用的时候,我在临时的计聚上,这个是可以的,而且我们Spark的本身的特点就是它是内存级的计计算框架,它本身计算速度就很快,即使你刚刚加载进去也是秒级反应,所以你没有必要,也没有没有那个必要,必须必要非得把一大堆数据的结果都先入库,没有必要,你入了库可能根本别人没用,多浪费啊。所以说呢,将来你的应用场景是,如果将来有一个大数据的计算,但是呢,你希望延迟到当用户调用时再去计算的时候,你就把这个函数给我加一个LA,你的性能就会大大提升啊,不是不是提升一点啊,是大大提升,可能你觉得说加一个累能起这么大的效果吗?其实有时候优化就是那么一点点。
16:05
我以前在这个公司工作的时候。我就觉得代码太复杂,怎么可能优化的出来,可能怎么优化的出来,比如说当时我们在做数据通道的时候,我做一个什么功能呢?分享一下,我当时给我一个任务,要做这么一件事情,你们也可以想想怎么实现啊。我当时做的是一个就是数据通道,类似于像QQ的那个服务器,服务器呢,我我们那个服务器要支撑支撑多少人在线呢?当时设计的目标要支撑1000万人同时在线。这个其实目标并不大,但是呢,要求只能在普通PC服务器上,服务器上跑,没有那个特别强的那个服务器。啊,当时我们要这个设计出来过后呢,我设计的一个方案就是里面有个最核心最耗费资源的是什么呢?就是保存和查询用户在线状态这个功能。大家听我说,就是当时我做数据通道嘛,两个人聊天,比如你像QQ聊天的时候,我要知道这个人有没有在线,有没有离线,他的IP在什么地方,我要发一个哈,怎么给他传过去,我就干这事。
17:12
其中有一个最核心的就是你必须要在服务器拿到这个人的在线状态,那么客户端是怎么做的呢?就包括你们像现在玩的QQ,其实你们你们玩的QQ,它每隔一般是每隔五秒或者十秒会向服务器报告他的状态,说我现在在线,我现在离线,因为你不报告,服务器是不知道你你在线还是离线的,比如说这个手机,这个手机为什么有辐射,你知道吗?因为他每隔一定时间,它会向他离他最近这个基站发一个信息,说我在哪里。你你知道为什么你你你的手机拿到,比如说你你你你到成都去了,你你到这个到这个云南去了,为为什么你打电话那边就能通啊。说老师这个我从来没想过,因为那个中国移动中国联通有个有个有个服务器中心,你每个每个手机或者客户端走了过后,他会向他最近的那个基站报告我在哪里,你不然的话,别的用户怎么找得到你啊。
18:14
嗯,因为大家都要走服务器,其实你们将来写这种,呃,即时通讯软件也是一个道理,那么我当时要做一件什么事情,就打通这个,打通这个,打通这个服务器的通道,其中最耗费资源的就是你怎么知道这个在线,因为我们一个好友,比如A好友有100个用户在线,他有100个好友,那么100个好友。在线状态要实时更新。这个压力非常大,我当时设计的方案很简单,特别简单,特别幼稚,干什么呢?我把每一个用户,我把每一个用户每隔五秒给我报告的状态直接写在MYSQL数据库里面去。你想一想,1000万同时在线。每隔五秒。每隔五秒有1000万个连接要指向MYSQ。
19:04
就几乎就已经。几几乎夫妻就贪了,这还不算,这还不算。还有一个更恐怖的事情,因为你除了要去记录所有用户在线状态之前,你还要把某一个人的好友的状态推送给这个QQ。比如说你,你有一个QQ,你有100个好友。我我要每隔十秒或者五秒把你100个好友状态推给你,然后你的客户端还要更新,你想这个就说相当于在1000万次里面,还要去乘以一,还要乘以100。有1000万乘一百十亿次的查询。当时我写完了,我还挺高兴的是吧,我这个写的太稳健了嘛,结果这个服务器这样去写,基本上不要说1000万人啊,就是你一台1000个人你都撑不住。那我觉得这个东,然后我们那个,当时我们那个领导,就是我的那个直接负责人,是新浪的第一任CTO,技术非常牛啊,就非常牛,他说你这个代码。
20:07
虽然说看起来好像没问题,在这个测试环境里面,我说没问题啊,我他说你测试环境有多少人,我我说不少,100多个人啊,100多个人算什么呀,说你要这个稍微多一点,你吃些服务就瘫了。他就开始给我优化,他说你这个其实并不难,你要怎么优化呢。啊,第一个你的这个你要分析你的用户在线状态,其实没有必要写数据库,因为用户状态它不是一个特别重要的信息,你比如说一个人的重要信息是什么呢?他的这个,呃,他的姓,他的姓名,他的地址,包括他的这个QQ的这个QQ的经验值等等,比如我们银行信息肯定就是我们的余额,最重要你的状态这次丢了再给你发过来再更新不就完了吗?他说你干脆啊,就把整个这个这个QQID,每个QQID直接给他放一个BY者写一个数据结构,写一个数据结构呢,你用那个地址,用地址不有这个地址结构,比如说用两个或者三个字节保持一个状态,然后用地址通过加减地址的方式找到这个块,然后直接把它那个,把它那个对应的那个信息,那个状态提出来,用0123表示不同状态,然后交给客户端,客户端对0123进行一个解析。
21:19
哎,他说这个东西他他提了一下,我就突然发现,哎,你看这个思路太清晰了,但是我还是不会做,我说你帮我写一下吧,那哥们,那哥们真的帮我写了一遍,写完了过后,真的啊,各位同学,那个东西一上去过后。真的能支撑1000万在线,当然我们不是一台机器,我们是分成分成三级的,大概也就20多台,普通的PC能支撑上百万。所以说这个优化其实没有你想的那么难,但是你想不到那儿去。那就很难,包括你们以后大数据的优化也是可能就是个小技巧,你比如说这个叫做惰性函数,可能你一加诶,突然发现原先我我这个功能可能只能支撑这个111亿次的计算。
22:07
1亿次的一个这个量,当我这个一把这个例子一加过后,发现很多没有用的,这个计算干什么呢,节省了。哎,那突然我更就是不是支撑1亿了,我可能支撑100亿,说到有时候优化呢,同学们不要不要觉得好像很麻烦,可能就是一个微小支出,就好像同学们在现实生活中是吧,其实其实有时候你发现一个学习技巧就是那么一点,好了,这个我就不不说了,同学们那么惰性函数呢,我给给大家板述一下好的。那惰性函数呢,老师,呃,刚才呢,也也说了一些东西,我们把它进行一个简单的板书,说一下惰性函数的一个由来,好,这是惰性函数,对不对?好惰性函数,那么首先呢,我给同学们说了一个应用的场景。就是什么时候咱们可能用到因这个,呃,这个多性函数呢,很简单,就是当我们啊,当我们需要这啊。
23:10
当你可以将耗时的计算推出到绝对需要,需要的时候,我们就可能使用到这个惰性函数,然后呢,我又给大家画了一个简易的图,来帮助大家理解这个多形函数的一个使用的一个价值。好,我把这个图呢也给同学们板书到笔记中去。好,这是我们的一个小图。好的,我把它放到笔记中。好,这是一个应用场景,那具体来说呢,我们这简单回顾了一下Java是怎么实现的。对,我说了一下Java,它实现这个懒加载的一一种简一一个简单的代码,对吧?诶其实我们的单利模式就是这种形式来实现的,对,那么我把它呢,给同学们放到这。啊,来截一个小的表格,紧接着呢,我们讲了,就是在我们SC里面,它是具体怎么实现的呢?它是这样实现的,对吧?案例这是他的一个介绍,就是他的案例,包括细节,我们一次性的拿过来。
24:14
啊,我们一次性的拿过来。好,这是介绍就是惰性函数的啊。就是多性。惰性函数的介绍,诶,就是具体来说它是怎么用的。把它放到这个位置。标题三,然后呢,案例演示,案例演示标题三。好,然后呢,这边有个注意事项和细节,标题上注意事项我说了两点,一个是lazy啊,不能修饰啊,不能修饰VR,第二个呢,就是声明一个变量的时候呢,如果加内该变量的分配也会得到得到推迟,我把这个呢也给同学们写到这里来,好,最后把这个案例给它绑过来就行了,案例在哪里就在这里。哦,就在这里,大家可以去,呃,待会自己愿意跑一下也可以跑跑。
25:04
好,同学们,那关于惰性函数我们就先介绍到这里,截取一段视频。
我来说两句