00:00
那下面呢,我们来给大家看一个,一个东西叫做管道,这个呢就要画图了,这个挺挺挺有意思的,但是理解起来呢,有一点点小难度,有一点点小难度,大家看啊,问题来了,我们先看一个需求,还是先抛一个问题引起大家思考,同学们看,我们现在有一个需求,各位朋友要计算一到200的各个数的阶乘,这个很简单,说白了就是一,一直乘到N嘛,这个大家都会,并且把这些数的阶层放入到map中。最后显示出来要求使用go grting叫做GR来完成,那么这个题对我们来说有难度吗?没有难度。我个人认为大家应该可以做出来了,因为说白了他就说让你用携程去做啊,让你用学程做,那是不是很简单,我们使用这个GR来完成,效率高,但是会出现一个并发和并行安全的问题,提出一个新的概念。
01:03
说老师没有什么问题啊,大家看啊,这个问题我们先写代码,你们看问题在什么,那么当这个问题产生过后呢,我们就提出了一个思考。什么思考呢?就是不同的growth之间如何通讯的问题。如何通讯的问题,好,同学们,现在呢,我们来一起完成这个啊,这个代码啊,就是看一下怎么求一个数的阶乘,提出一个概念,代码怎么实现,我们来看一下第一步。使用第一步,我们使用GR来完成,看看GR并发会出现什么问题,然后我们会去解决第一步,第二步,在运行某个程序时如何知道是否存在资源竞争的问题。就是这个资源竞争怎么去做,方法很简单,在编译的时候呢,我们可以加一个race,这是我要去做的,好,那么现在同学们,我们开始来完成这个东西啊,我们就是求阶层,求阶层那怎么做这个事呢?
02:07
那怎么来做这个事呢?来,我们写一段代码。我们写段代码,OK,那么这个时候我们还是新建一个文件夹对吧?新建一个文件夹我们叫做channel的,呃,就是引出这个China的必要吗?还叫GR吧的一个案例。GROUT。好DEMO。好,诶已经有了,那就零二吧,零二。好,我们新建一个文件夹,May。当然新建一个文件。新建一个文件面点够好,我把我的需求先拿过来,主包import。Import。好,把我的要求拿过来,我的要求是这样子的啊,同学们看一下。
03:00
在这里。在这里。他说要求去计算一到200的各个数的阶层。各个数的阶层。好,那么我们怎么来完成这个事情呢?好,怎么来完成这个事情呢?来,它的要求是用G来完成,那我首先写一段代码,主函数。好,我先我写一个函数啊,这里思路是这样子的思路,第一步我编写。好,我这样子,我编写一个函数,编写一个函数来干什么呢?来计算。就来计算,来计算。就是来计算各个数的一个阶层。对吧,个人数的一个阶层。并放入到,并放入到。放入到一个map中。并放入到一个map中,第二点我们应该分析出来,既然你将来出现的一个情况是,你可能起很多这个携程,比如说我们企业。
04:08
我们我们启动这个四个或者五个对吧,我们多起几个,我们多起几个几个携程来完成,那么这个时候呢,效率才会高嘛,第二步我们这个map呢,Map是需我们起的啊,我们启动的这个携程,携程呢是多个多个。多个,然后他们统一的去干什么呢?统一的去访问这个map,统一的。统一的将将这个结果阶层的这个结果结果放入到哪里呢?放入到map中。这是第二点,我们分析出来了。那你为了让你为了让这个,你为了让这个结果放到这个map中,那这个map是多个携程都要访问的,那你只能把这个map呢,在在初始情况下,你只能把它做成一个全局的,因为大家都要去访问,所以在这个时候呢,这个map应该是个全局的,从这里看看啊,Map应该做成。
05:10
做成一个全局的。哎,这就是我们分析出来的三点对吧,那三点呢,就是待会儿我们要做的这个东西,好呃,那现在我们开始来做这个事情啊,怎么来做呢。好,我们来写代码了,我们来写代码。怎么写这个东西呢?它一共是一到200的这个各个数的阶层,各个数的阶层。那我们启动多少个携程比较合适呢?我看一下啊呃,启动三个四个也行,咱们启动四个也行,对吧,那写先写个函数。Funk。Test。对,他是。好。然后这个地方我们还得先定义一个,呃,全局的一个map,全局的一个map,对全局map,那咱们先定一个变量吧。
06:06
对,Map,那这个map我们到时间是放什么呢?放这个值进去,就是有了一个结果,我们叫它放进去对不对,有个结果把它放进去,所以说我在这呢,写一个map结果,比如说map my map,对,然后等于什么呢?事先我们给它分配一个,分配一个空间,比如说。我放这样一个结果。啊,放这样一结果,第一个呢,就是各个数对吧,它这个数是什么,这个它对应的阶层呢,也把它放进去,我看我这输出是什么啊,我看我这设计的输出是什么。将来输出的结果是这样一个结果。啊,就是map,我看是怎么设计的map哦,把各个数的阶层放入到map中,Map中最后我们显示出来,那就说整个这个map呢,是最后把结果都放到这里去,最后我再遍历这个map就完事了,是这意思吧,最后遍历这个map,好那就简单。
07:07
那这把它设计到这个地方来卖,事先给它分配一个十个空间的大小。好十个空间大小,这个还没用到,所以说报错。嗯,那这里面呢,我们来考虑一下怎么去做这个事情。待会儿我们请几个几多,请几个学生去做,那这个数怎么传进去,大家想一想。数字怎么传进去呢?开启100个。开启200个携程,那你关键是它要求一到200这个数是不是分开呢,从里面传到。里面,然后里面写个那个。和那个。啊,你你你说一说你的思路怎么写。就是电子。
08:01
一个I。对,那就简单,那就说多起几个,就说这个时候我们直接让每一个函数都去做这个事情是吧,那也可以这样做,我们来试试看啊,看看这个刚才就是小夏这个思路能不能搞定这个事怎么做呢?第一个我先写个N。In。对这个int,那这个int呢,是不是它可以是传一个数,我就把它那个阶乘求出来是吧,这个没问题,好,所以说我就for循环,那怎么for循环呢?就I等于一是不是,I小于等于多少呢?N是不是,然后I加加,I加加完了过后,我把这个结果先记录下,结果假设为。是不是写成一呀,写成一,然后我怎么怎么算这个东西呢?R乘以对乘以等于I,就是我不停的去乘,最后这个RS呢,就是我们最后这个数的一个结果,是这意思吧,好,然后注意听。
09:04
把这个结果做好了以后呢,我们显然。循环完了过后,我就把这个res放入到这个map里面去,My map里面去,对不对,好就肯定是这样写的嘛,这里我们。我们将什么玩意儿呢?RS这个结果放入到哪里去?My map中?My map中好怎么放?非常简单,My map走第一个值,就是你当前这个N。可以这么说吧,就是这个N,它对应的这个阶层这个值呢,我们认为就是res。这写完了,有这个函数,这个test是干什么呢?这个test的函数就是就是计算。计算N的阶乘。N的阶层,然后把这个结果,然后将。将这个结果,这个结果。
10:01
结果放入到。结果啊,放入到哪里呢?放入到咱们的这个map中。卖不动。好,这就写完了就放进去,那放进去过后,我们现在开始怎么办呢?我们用起斜程多,我们多起几个斜程来完成它,就是人家是要求用携程来完成嘛,对好,现在这里啊,我们这里开启。这里开启多个。多个携程。携程完成这个任务。那最简单就是说你不是要求一到200个吗?那我就起200个,对,200个最多,那玩一下for I等于一。I小于等于200 I加加,然后我这很疯狂啊,我直接go它什么呢?I大家可以看到相当于我起了多少个呢。
11:02
我起了200个。那也就是说你们可以想象到,当我们一运行的时候,我们就会把什么呢?我们就我们就在这里啪啪啪一共启动了200个携程去帮我们做这个事情。那每一个人,每一个学生就完成一件事情,说你给我传递的爱,我统计是不是,并且把它放进去。啊,相当于起了200个,那起了200个过后呢,我们来这里输出结果。这里我们输出结果。对吧,就是map里面这个结果有有哪些,我们可以把它把它遍历出来看一下,就遍历这个结果。理论上是要写的吗?便利这个结果。便利这个结果。好,这个结果大家想一想啊,我们目前能不能马上便利?对,我们能不能马上变利,大家看啊,如果说我们马上变利,会发现什么都没有可能。可能什么都没有,你们可以看一下啊for,我们遍历这个,呃,Map应该怎么遍历,很简单。
12:06
是for是不是就可以了,第一个是它的I,第二个是它的值是不是,然后呢,等于range谁呀。就是map。Map,好,我们把它打印出来,看一下PTF,我们可以这样写。Map走。百分D等于它的一个值,这个值呢应该也是一个整数,好的,那走一个换一行,然后第一个D呢是I,第二个D是V,好,我们先来看看,如果按照这个模式啊,这边有个问题。这打了个空格,不小心大家看我们这样做,其实已经按照他的要求来做这个事儿了,他说要求使用节省,而且按照这个思路,大家应该也也能理解大致是什么,但是我们运行过来过后,我们发现跟我们想的有一些区别,这就是问题之所在。
13:04
大家看一下我CD到刚才的GR02里边去,注意听DRCD到组的这个目录,然后DR go run main.go好。同学,看到什么都没有。哎,有问题说老师你这不是起了这么多斜程,为什么他一个都没有呢。张大一想一想,为什么一个都没有?怎么一个都没有呢?班长。你就说说原因,原因是什么?原因是什么?是不是上午我曾经讲过一个特别重要的一个知识点,大家回忆一下,我在上午讲了这么一个特别重要的一个知识点,我说它的一个主线程和携程执行的一个流程。那就说你在这里开启了,我在这种做循环,你开启了很多很多携程,200个携程,但是这个携程它还没有执行完毕的时候,你主线程是不是已经结束了。
14:09
你主先主先生一旦结束,你这个你下面的学生有没有执行完毕,我根本不管,所以说一个结果都没有,是这意思吧,那现在已经很尴尬了,说老师那我怎么办呢?我们现先不两么多啊,我们现在先一步一步的解决,现在我在想,我假定,我假定我让你在这给我跑十十秒钟,我看你有没有结果。就说我一个最笨的方法是。我先一步,硬币,一个最笨的办法就是我在这个主线程这一方,我等你。我痴痴的等你,我等你什么呢?我在这等。What,哦,不是这个图啊,哦,是这个图。在这我在这个主线程,我先不要着急的走。我先等你十秒钟,这是最笨的办法。当然大家可能会说,诶,老师,为什么等十秒钟不等20秒呢?
15:00
对,那我等20秒,你会说为什么不等30秒是吧,这个等长等短其实已经很麻烦了,其实我已经提出一个一个问题了,就说你现在问题是主线程。就你你的这个主线是什么时候退出,和你这个携程什么时候完成,已经现在缺乏一种机制了。他们之间必须要有一种机制,现在呢,我们还没有好的机制,我们只能先来玩一个简单的来看。来吧,各位同学,现在一个最简单的办法,我就等你。我休眠。休眠十秒钟。休眠十秒钟。但是这个地方他其实很尴尬,其实对方已经提出一个问题了,说十秒钟。不合适,就是长了短都跑,我先暂时等十秒钟啊,那怎么写,那就这样写,Time time time.sleep走,然后呢,time.second。ECO10秒乘以一个十嘛,但是呢,我要以一个包包。
16:01
我要引这个汤包,好,各位同学,我们再跑一下。各位。走。好,同学们看到我们又很郁闷了,这个时候他报的错误呢,很恐怖,哎,他报了一个F塔A。Call。Con my什么意思?并发向这个map进行了一个什么操作?操作画一个图,可能大家同学现在听的有点蒙圈了,说老师你赶紧给我们说一下,为什么各位朋友我们不画,二说老师你现在是不是主线程起了起了有二两百个携程,200个携程,我我没有那么多精力画200个啊。我就点用这个点表示了好不好,老师你画200个呗,我画200个这个框框,那我们直接就下课了,假设这个点点点到200了,各位你这200个携程其实其实你们是不是都在同时操作同一块的空间,这个map空间。
17:06
各位你是不是样式,这是我们麦的这个空间。空间你没有任何保护机制,你没有任何保护机制,也就是说目前出现问题的原因是这样子的,各位朋友。来,我们画一个图,这个图呢。来看清楚了,就说你这个主线程现在整了200个携程,这两个携程做了什么事情呢?他们在做同一件事情,什么事,就是做这件事情拿到一个N计算完了后往这个map里面写。完事了,你往里面写,很痛苦的,你往里面写,你看现在这个家伙在疯狂的往里面写。这个家伙。写完了过,他又接着往写。好,然后呢,他他不是写完了过后再写啊,他同时写。他去写,因为你你现在至少有四个CPU在用啊,你现在四个CPU,你四个CPU可能真的是。
18:01
在同一个瞬间都往里面写,大家都知道我们往同一个数据数据空间同时写的时候,就会出现一个并发问题。写不能不能用,这个地方必须要保护读可以,你们学过那个读,比如说我有一本书,我有一本书告诉大家啊,我有一本书,我们让两个人同时看一本书没问题,就好像看电影,哎,韩老师把这个电影一拍,你们下面多少人都可以同时看看没问题。但是写书不行,比如说现在我有我有一张纸来,韩老师在这写,写的时候其他班长还有我们副班长都,哎,我要写这肯定要出问题了,所以说这里面就报了一个非常经典的错误,什么错误呢?就是这个叫做。Con啊concurrent就是并发map的一个写操作,这个是不行的,好问题已经看到了哈,看到现在其实我们已经暴露了两个问题,大家看出了没有,现在我们代码已经出现了两个问题,第一个问题。这儿。没有保护机制,没有互斥的一个问题,你这会出现这方有一种可能性的错误,就是。
19:07
经典的叫做这个错误,这是第一个问题,已经抛出来了,我们要解决。第二个问题。等多久?这是第二个问题。那么这两个问题呢,其实我们可以解决,我们先来看第一个思路啊,好,问题已经抛出来了啊,同学们讲了半天,其实把这个问题抛出来了,那为什么要出现这个问题呢?我们还可以通过另外一个,我们刚才是通过运行看到的,其实还可以一种方式也可以看到这个问题,就是我们可以通过这个go build。带一个杠瑞也可以看到这个错误,来同学们看,比如说我来运行一下。大家看到。我把它我我把它那个运行一下啊,同学们go。Build b bil-race,这个race就是竞争的意思。
20:03
如果带个瑞士的话呢,你这个程序如果有竞争关系,就是资源有竞争的时候呢,他会把这个把这个数据给你信,把这个信息给你打出来,那我给他再再演示一下看啊瑞士,然后呢,我跑一个叫什么呢?叫做刚才写的main点勾。好,我执行编译。编译好,编译完了过后呢,我们可以看到在这里呢,产生了一个main.ex我来执行它。好,等待,耐心的等待。耐心的等待十秒钟。十秒钟过后你们会看到有东西啊,我我十秒钟可能等的有点久了。好,你看其实有数据,各位朋友有数据。大家看到这里面有个经典的错误。Found。四。什么意思?这句话就是说我告诉你啊,我告诉你,我发现有四个数据,就是他可以准确的告诉你,其实在写的那瞬间,有曾经有四个数据产生一个竞争关系,就是往里面同时写出的问题。
21:09
看到没有,其实地方已经有结果了,但是呢,他说有四个数据产生一个竞争关系,这个就可能出现出现一个问题,好,我们现在解决这个竞争关系的问题啊,好,同学们先把这个问题板书,我们再提解决方案。好,Channel管道的一个需求和他的问题已经出来了。我们往下拉。OK。好,这是需求已经有了,不着急啊,同学们,我们慢慢讲。都大家讲清楚,标题二在这个地方,标题二在这,好,我们刚才提出了一个问题,也发现了他的问题,这是我们将要讲的这这几个问题。好,我们讲了思路分析,代码实现。好,这是刚才讲的一个需求,这是思路的分析。
22:04
啊,思路分析,我刚才提出了两点,第一点我们怎么做。第二点,我们做了一个代码的实现。我们做了一个代码实现,那么我们发现这里面存在一个这样的问题。啊,存在这样的问题。一。第二个在运行的时候呢,我们发现有这样一个东西,那么原因是什么?它的示意图看一下示意图就是刚才它之所以会产生这种问题的原因,是因为我们有多个携程同时向这个脉搏空间里面写东西。问题就在这里导致的。来,接着往下看。示意图有了。好,有了这个示意图过后呢,代码我们也有了,代码其实也有,但是代码的问题它比较严重,对吧,我们现在对应的代码也放在这。啊,代码实现代码实现代码呢还不完善,但是呢也算是写出来了。
23:05
也算是写出来了,好,我给他来一个小小的表格,问题已经在这了啊,好,来,这次我们已经提出了他的问题,以及他的问题的原因说清楚了,建议这块呢,我们先关于这个问题本身,我们先说到这。
我来说两句