00:02
核心组件,Event loop元宝剖析。同学们还记得哈,我们在前面呢,其实已经分析过event lo,还有event loop group相关的源码。但是呢,我们一直没有去真正的进行一个动态的分析,就是说我们这一个。就这我们以这句话为例,我们以这句话为例,这里面呢,是创建那个IO event group group,而这个group里面是不是它的核心组件就是n IO event group。而且呢,我们也知道在进行一个嗯,监听或者是处理客户端来的请求的时候呢,其实他本身是一个循环。是不是一个事件循环,在这里进行一个一般的loop循环的去处理相关的事件。那么到到底他是怎么来进行进行这样一个操作的,从源码这个角度我们来进行一次分析。
01:04
来吧,打开我们这一段源码。来进行相关的分析。首先呢,我们先来看。我们先来看。关于。Even the loop。它的呃,源码在看这个源码的时候,我们首先呢,先给同学们看一下n I event loop的一个继承图,这个图呢非常的重要,我们来看一下。同学们看。我们n event lo这个类,它继承了是single thread event loop。对,也就是说它是一个单线程的event loop,就是一个no event lo,它对应的其实是一个单线程的event loop,而这个类负类呢,它又实现了这个接口,就是我们所说的event loop这个接口,同时呢,它继承了。这个叫single thread event executor。
02:03
咱们看这这个关系,那重要的地方我标成一个红框,待会儿呢,还会分析继续往上走,还经历了经历了一系列的继承或者实现。我们重点看红框,还有一个特别重要的叫schedule ex service,这是个接口,然后最上面最顶级的呢,是H这个接口。大家看这个关系理解了。看到没有,而且大家有发现,甚至呢,这边他还有一个这样的接口叫event event group,看到没有好的。那么基于这样一个图呢,我们就来做。相关的分析,首先,同学们看到的schedule service这个接口表示的是一个定时。任务接口的loop可以接收定时任务,我们经常说的是可以含有相关定时任务的,它凭什么可以去接收相关定时任务呢?就是因为他实现了这个接口,我们打开这个接口看一下。
03:09
注意听啊,同学们这些呢,相对有一些难度,我把这些关闭都关闭都关完。然后呢,我们。打开一下。造一个。同学们看。Schedule h service里面有相关这些方法,大家看是不是很熟悉的。你看。Schedule在提供可以放入我们相关的这些信息。D内就是延时多长时间,然后呢,时间单位,下面这个是不是还可以干什么,是不是我们还可以传一个level,是不是也可以指定内和时间单位。是不是这样的,同学们,所以说基于这样一个原因呢,我们就说我们的event loop可以接收定时任务,就这么来的。也就是说我们这个loop里面,它含有一个定时任务的队列。
04:03
那么的loop接口呢?在他这个文档,在net接口文档说明中说到,这个接口的作用是一旦China注册了,就会处理China对应的所有IO操作。还有一个就是我们要看一下另外一个它上面的一个核心的核心的一个呃组件叫single thread e ecuor,它表示是一个单个线程的,单个线程的线程词,我们来看一下。也就是这个东西。这个。好,同学们。我们来搂一眼。大家有发现哈。Single thread event eor,它其实是一个线程词,为什么说它是线程词呢?大家看它是不是可以run all task方法是从这过来的。对吧,Run all tasks。Run or,好多,这个重载的方法特别的多,还可以加任务。
05:02
看到没有,可以remove task。而且加的任务和加任务,大家看是不是就是抓加一个实现了runable接口的这么一个对象。我我一看是不是软接口啊。没问题吧?好,接着继续往下阅读。下一个呢,我们看lo是一个单立的线程池,里面还有一个死循环,一个死循环的线程不断的做出三件事,哪三件事情呢,监听端口,处理处理端口的事件。还有处理队列的事件,每一个event loop都可以绑定多个channel,而每个channel呢,始终只能有一个event loop来处理,那现在呢,我们来看看他是怎么来处理的。同学们看。在这个e IO event里里面呢,我们我们先来分析一下相关的方法,其中H就是这个H,这个接口呢,下面有很多的子接口和实现子类,看到没有,那现在呢,我们来分析,其中有一个叫做刚才我们看到的叫single thread eventcuor,我们看一下其实就是这个东西这里面。
06:11
就有一个我们现在要马上分析的方法,叫什么呢?叫这个,我们把这个拿出来看一下。找一下。这个方法呢,特别的重要,大家看他是干什么的。是不是因为我们这个loop它上面的。上面的这个组件就是这是一个类,这个类里面有有一个H,所以说我们疑问的loop是不是也可以去执行H啊,他是怎么执行的呢?Wrong label,一个task。那这里面呢,我们看他是怎么做的,这边很关键,待会我要开始第bug了。他先判断你当前这个线程是不是往这往这走,就这句话。是不是返回一个不,它怎么样呢?首先判断该的loop的线程是否是当前线程,如果是,则直接加入到任务队列中,就这个。
07:06
没问题吧,如果不是怎么办呢?如果不是怎么办呢?就尝试启动一个新的线程。由于线程是单个的,因此只能启动一次,再再随后再将任务添加到这里面里面去,好,这是第一句话,待会儿我马上要第bug了。先把这些说完,我们在第八个,如果线程已经停止并且删并且删除任务失败,就执行拒绝策略,就哪句话呢?就这句话。哎,这这句话啊,这句话不好意思就说,如果is shutdown,并且remove task。在这种情况下。在这种情况下呢,我们就干什么呢?去执行拒绝策略,默认是抛出一个异常,如果爱的task wakes up是boss,并且任务不是一个这样的,这样的一个类型的,就唤醒select,也就是说这个地方呢,它会唤起什么呢?Wakeup会唤醒阻塞的select线程,立即返回。
08:05
那这个地方,这个地方我们现在要追就比较困难,那现在我们我们这样子追,我们先把断点下在这个位置。我们看看。是不是这样子来启动一个线程的呢,对不对,好朋友们,那还是老规矩,我们找一个代码来进行测试就用。这边的e server吧。我们在哪里下断点呢?再再接往下一段点。没问题吧,这是下个论点,然后我们看看此时此刻。是不是已经有其他专业,我们先把这些专点先删掉。不要的哈。我先删掉。现在的断点呢,就在这儿有一个断点。没问题吧,同学们懂,然后呢,我就debug server,跟着老师思路。你们待会就能看到整个这个流程。啊,负责的讲,会看到整个这个流程,好,首先我们往下走一步,此时此刻。
09:03
此时此刻这个线程呢,它肯定第一次进来,它不是这个当前的,对不对,它所以说它会进入到else,也也说这个是返回一个for。返回一个force,然后呢,我们听到这个start thread。大的就是启动这个线程,他到底做什么事情呢?追进去一看哦,他下面做这样一个事情。做什么事情呢,Do star?这个是它一个核心方法,往下走进来了,再咱们追进去。OK,大家看首先呢。我们看到这里面最核心的方法是哪一个?来,我们一边阅读一边看。好的。这这个地方啊,我们我们现在可以追到这个里面去了,追到这个地方single thre event.z使用这个是不是就是真正启动我们这个event loop。嗯,这个这个循环呢,是不是,所以说我把断点下到这里来,我让他直接奔这儿来。
10:04
来了。对不对,就single thre event this,点这个this呢,就是当前这个,大家看event是不是event loop没没有问题吧,同学们,那现在呢,我们进到这个wrong里面去,就一目而了然了,哦,这个wrong做了什么事情呢?好的,大家看这个RA做的事情,就是我们正要找的那三件事情,哪三件事情,打开我们原先讲的ninety模型,这下子就。完全对上了。我们在讲Nike模型的时候,大家应该还有一点印象。哪里,在这里是不是。他进到这里面来了,过后他有一个S。有个process。Select case,还有一个run all tasks,那么我们看看这个地方是不是已进到这来了呢?大家看这是不是一个select?
11:02
是吧,下面接着看。接着往下看。是不是这里面有一个。什么select在这?是不是它是来处理选择到的case,就是我们所说的selection case,然后这个处理完了过后呢,根据IO的一个比例,这个IO比例主要是他要看执行我们这个队列里面的任务的一个概率,那下面呢,大家看这还有一个非常重要的方法哪里啊。往下看反了你啊。在这个地方呢,还有一个特别重要的方法。往这走,不管有没有,呃,处理完是吧,不管有没有异常,诶,同学们干嘛了?是不是有run all tasks,就是我们对应的这个风险。是不是三部曲,所以说待会儿呢,我们可能要重点的就是分析这三个方法。因为现在我们已然追到了这个循环,那下面我们就要去看select。
12:04
Process case,还有run all tasks到底做什么事情,这样就把它说清楚了。来,我们继续继续来阅读一个代代码。呃,那么刚才呢,我们已经说到,如果线程已经停止,并且这个这个刚才已经念过了啊,就是这。下端连也说了第八个a task,还有一个off task方法,这源码呢,大家可以看到,如果这个任务等于空,我们就怎么样,在加这个任务的时候,我们现在,我们现在可以回去一下返回。我们先返回去啊,同学们。诶返回的话用这个打到这儿。反映到这儿。返回到这里呢,同学们看这里是不是,呃,它有一个I的I爱的task,这个爱的task呢,就是现在大家看到这段代码,如果你加的个任务为空,那就直接怎么样抛出一个空指针异常就long point exception。
13:03
否则的话呢,就offer他offer不就是提供对吧,提供这个任务给他。啊,如果失败了就reject。这个task。那下面这个方法是干什么呢?Off task,他先看一是shutdown,如果你是一个shutdown的啊,已经停止了,就reject拒绝,否则就什么呀,大家看这个地方,你们看懂了吗?干嘛呀,这个事情在干什么呀?Task q是不是我们以前讲过在event loop里面,他维护了一个task q,还有一个schedule task q在这个地方是不是就把这个任务扔到我们这个队列里面去了,能理解了吗?哎,所以说老师呢,给大家追到这里,这里面来,好接着往下走。没有,诶,这我要重新来下个断点了,同学们不着急啊,我这里面直接给你下断点。我们再来第八个。再重新来debug一下。好,这样子我们就看得很清晰了,走起来。好,我现在呢,往下走,Start的start的这个thread是不是就是相当于把我们这个循环跑起来。
14:08
不管是这边还是这边一样的,对不对,跑起来过后,是不是这边他还有增加这个任务进去啊,那下一个。倒出来,那大家看这个task现在为空吗?显然这个地方它不是空子,对不对?这个任务的真实类型其实是obstra China下面的一个类部类叫abstract ona,那现在我们可以追进去lawyer。朋友们哦。不为空,不为空干什么?进到这里面去,进到这里面去是不是要执行task?Offer task,那就把这个任务往什么准备,向这个task q里面扔,好,我们进去。进去了,现在你下当吗?现在现在你是下当的吗?好接着往下走,没有现在这个不是下当的,所以说他现在就把这一个task扔到我们这个队列里面去,那这个队列到底是什么玩意儿呢?朋友们看这个队列。
15:00
是不是它是一个RQ。现在呢,没有东西对吧,所以说你如果有兴趣可以往里面再继续跑。继续放,看到没有offer看到没有往下继续是不是做相应的处理啊。是不是做相应的处理,OK,我先反馈。回来了再返回。现在是不是就把我们这个task执询完毕了,好回到我们这边文档继续看,那么这个任务做完了之后,我们再看n no event loop的负类single thread,呃,这个event里面的十大的十大的TH的方法是不是经讲过了,刚才我们已经讲过了,当执行这个方法的时候呢?呃,我们看仔细看这个代码就行了,Star thread刚才已经看过了啊,就是这么一个do start thread该方法。就是这个方法呢。呃,首先判断是否启动过了,保证even loop只有一个线程,如果没有启动,就尝试做下面一个状态的改变,然后如果已经启动,就执行刚才我们追的那个do star失败,如果失败就进行回滚。
16:13
那这个do start的,呃,SH的方法,其实刚才大家已经看到了是吧,Wrong,然后这里面是它的核心代码,我们是不是也也刚才已经追进去了,就到这里面去。好,那我们接着看。嗯,他在执行这个方法的时候呢。在这里。执行当前的no event loop的run方法。注意,这个方法是一个死循环,是整个event loop的核心。对,在BY了这个块里面呢,也不断去修改这个状态,对,他会把这个状态改改成相应的状态,那么也就是当前loop结束的时候关闭线程,最后还要使循环确认是否关键关闭了,因为它它会再次确认,否则不会break。
17:00
那下面呢,我们接着看。嗯,这个run方法,我们在这个run方法里面去要看哪一个东西了呢,就是刚才我们看到这一个,呃。呃,哪个方法就是select,这这个run方法里面的三个部分,一个select。一个是select key,还有一个run or。那现在呢,我们先来看哪一个呢?我们先来给大家看select往这边追。Process select case,还有run or task,实际上上我们在前面已经说过了,有兴趣我们也可以追下,我们再去追这个方法呢,我们来看一下select怎么体现出非主色的来,同学们,我们回到这个start的方法里面去,这次呢,我重新再追一次哈,因为加任务刚才我们已经看过了嘛,下面没有什么可看的了,我就直接在这在。大的大的的这个方法里面再来看一下。还把断点下这我停一下,然后呢,朋友们我们继续来看一下。
18:02
各位。现在我们往那个select方法里面追一追,下周。下周进到这里面去追进去。追进去呢,我直接让他到do start。进来了。进到这边去。然后呢,我直接让他到single th event.this run进到这里面来,然后追进去。好,同学们看现在呢,我要知到这个方法,所以说我在S方法了,我直接下个断点没问题吧,同学们。跑进去。咦,他要跑这儿来啊,跑这来。好到我们select方法来了,这个select方法呢,我要注进去了。同学们看,诶有点意思,看这里。这个方法呢?就是。我们一前面一直说的那一个所谓的监听,他在干什么呢?大家看是不是也是个循环。是不是一个循环,那这个循环怎么去阅读呢?代码看起来有点多啊,有点多,我们一步一步的看。
19:03
我们一步一步的看,往下搂一下。针对三类方法来做一些解释。嗯,大家看。Thirty。这是代码吗?下面我说明调用select的select方法。默认主射疫苗,如果有定时任务,注意听这句话,如果有定时任务,则在定时任务剩余的时间基础上加0.5秒进行阻塞。当执行ex方法的时候,也就是添加任务的时候会唤醒,那就不要这句话了,唤醒select select,防止select阻塞时间过长,那哪里体现出阻塞疫秒呢?来同学们看一下。我们往这追那就往下走哈。我们现在已经到哪了?我们回到源码。回到这个位置,说到这儿,来,往右走吧,走。走走。
20:00
好。继续往下走。继续往下走。走。继续。同学们看。如果到这儿啊,看看这里面看到没有。有任务。如果有任务干什么呢?并且wakeup compare and set。在这种情况下都满足的时候,他会干什么呢?往下看一下。是不是呃,满足这个条件就进到这里面去,就把这个sad的C制成一个一,但是现在呢,因为没有满足,所以他就没有进到这里面,没有进到这里面过后呢,大家看在这个时候。他在这个面去又去调用这个S。这不就是刚才。看到这个select吗?是不是又进到这里面去了,这里面呢,它会。要传时间了啊,这这个还不是一样的,因为这边传的是一个布尔布值,这边传的就是一个具体的我阻塞的时间。
21:01
注册时间现在是默认是多长时间呢?往下看一下。现在这个阻塞时间其实是。一秒钟。对不对,默认主摄一秒。默认组织疫苗,然后把这个赛CN加一,加一过后又判断什么事情呢?诶,他来判断你当前是个什么事件。啊,所以说你看我这写的很清晰在这。看这句话。看这如果一秒后返回。呃,有返回值或者是select被用户唤醒,或者任务队列有队列或者是有定时任务即将被执行,则怎么样break?就跳出这个。对不对,那现在有没有呢,往下走没有,所以没有的话呢,他就不不去break,继续做这样一些相相关事情继续做。好,继续做,好,接着往下走,看到没有。
22:01
是不是继续往下走了,继续往下走呢,又回到这边来,看到没有又来了。又来了,看没有同学们。看到没有up?
我来说两句