00:01
单reactor单线程。单reactor单线程是我们reactor模式的第一种实现方式,我们来看一下。我们前面讲了一个基于NIO的群聊系统,其实呢,它就是单reactor单线程的经典使用。大家可以看到。它的一个原理图呢,是这样子的。这大家看到是不是他把所有请求发给了一个reactor,这个reactor其实有点类似于前面我们讲的。那个reactor模型里面的那个service handler,但是呢,我们这直接把它称之为reactor,它这里面呢,有一个selector。它可以调用select方法,然后呢进行dispatch。那如果说我发现你是进行一个连接请求,那么我就调用他的accept,就是接收器进行一个accept操操作,还记得吧,大家可以待会对照我们的代码来看。然后呢,在呃,这个连接好了过后,是不是下次下一次C端就会发送具体的数据,发送数据呢,我会去调用一个handler去进行读业务处理和send再发送回去,那同学们可以看到说,诶说老师那你在讲NIO的时候,你好像没有去创建一个handler,是的,我在这确实没有去创建handler,但是实际上呢,我可以,我可以把我进行业务处理的这些方法封装的一个handler,只是我们样去做而已,其实它等价,于是让一个handler去处理,明白我的意思吧。好,现在呢,我们打开NIO原先写的NIO群聊系统,我们对照这个图,看看是不是都能找到它对应的,对应的,嗯,对应的这些组件。
01:48
首先我们可以看到,在这里呢。我们看这有service。这个service,同学们可以看到,在这里它是不是处于一个listening的状态。
02:00
实际上它在这里呢,就调用了select select方法就是同学们看到的。这个方法。因此我们可以在这里认为select就是一个选择器,它在这里就充当了什么样react的角色,那么这个dispatch怎么理解呢?大家可以看到,他一旦发现。同学们看这里。他一旦发现你是一个连接请求,是不是一直accept acceptable acceptable,然后呢,他就调用我们的accept方法。在这里吧,Accept方法。Accept方法完了过后,是不是他就把这个请求下,就把我们的得到的一个socket channel注册到我们S上面去,下一次。下一次是不是就如如果说下一次的话呢,再去获取一个事件,就应该是一个读的事件,这个读的读的事件我是不是调的read data,其实呢,在对照我们这个图来讲的话,如果对照这个图来讲的话,相当于说是调用一个handler的read方法,也就是说其实我们完全可以把read。
03:09
还有一个。发送send for to our client封装到一个handle里面去,只是我们这么这么做而已,也就说其实也可以写,如果按照他这个标准的模型的话呢,可以写。一个handler。比如说我写个MY。Handler。对不对,然后呢,我在这里把什么呀,把我的方法封装进去,一个是read。Read。没问题吧,Read。Read data。然后呢,在public void什么呀,就是这个方法善。其实这里面我们的处理不就是一个接收,然后再转发吗。
04:00
是不是?所有完全可以这么去做。对吧,诶完全可以这么去做,那这里面你就换成什么呢,换成在这里进行处理,处理业务的时候。把这进行一个修改就可以了,就跟这个模式对应起来了,哪里这。是不是我们创建一个handler,然后呢,调用他的read方法完事了。在read方法里面呢,又去封装了,或者调用了我们它调用了它的send info to other classs这样子呢,就跟这个模式进行了一个匹配,然后再把数据回送回去,都在,就说读数据,业务处理,还有回送数据都在handle那。对象里面进行完成的。这就是我们经典的一个呃,单reactor单线程,那么同学们有注意发现,在整个单reactor单线程里面,我们的reactor还有handler这些其实是在一个线程里面,大家有没有发现,因此这种模型其实它的缺点。
05:01
也一目了然,就是如果有高并发的高并发,高并发的话呢,其实这个地方还是有很大问题的,因为你只有一个线程,那势必造成阻塞。要比如说你在这个handle处理的时候,又来一个C来来了,那你这边就有可能阻塞在这里,是这样子吧,那怎么解决这个问题呢?好的,咱们可以这样这样来做处理。呃。就是下面就有相应的解决方案啊,那在呃,就说。他这个单reactor的问题呢,可以通过什么呢?可以通过下面一种模式来得到解决,就是我们所说的这种模型,就是单reactor多线程来解决,那嗯,在讲这个单reactor多线程程的时候呢,我们是不是来给大家验证一下,就是通过我们NIO群聊,我们来验证一下是不是整个这个运行过程中都是在一个线程里面完成的。从而呢,说明这个单react单线程其实在处理高并发的时候是有一个瓶颈的,那么我们就以我们写的群聊IO的群聊系统来进行一个,呃,进行一个验证,那同学们看这个地方是。
06:14
我们的react监听的位置,所以说我在这呢,输出一下当前线程的情况,我写一个。监听的县城。监听线程好,我呢这样子用。点。Current帅的碟,Get name。这是把当前这个监听线程打出来了,然后呢,我们在哪里再输出它的一个线程情况呢?比如说我们在这个地方写一个。这是不是他把消息回送,呃,转发给其他客户了,那现在这里呢,我们也来输出一下转发消息的时候用的是哪一个线程。是一个。转发服务器。服务器转发。
07:03
转发数据。数据给客户端。输服务器转发客数据给客户端的线程呢,我们也输出来,我们看看这两者是不是一样的,来同学们。我们来运行一下。好。我们来运行一下,比如现在呢,我们先运行。Group China server我们运行一下。运营起来哈,跑起来主要是看输出。线程的情况是不是我们想象那样,大家看监听线程用的是主线程命令,然后呢,我用客户端来联想。跑起来。同学们看。好,来了一个,来了一个,大家有没有发现他上线了,上线过后呢,我们再来一个,因为他群聊嘛,至少我来三个吧。又运行又来一个上线的,我们再运行一个三个上线的。
08:01
同服务器这边我们看到有三个客户端上线了,然后呢,我们发送信息,比如说我这简单一点就叫HELLO100回车,我们看服务器端用的线程,它进行转发的时候用的是哪个线程,我们发现呢,它用的仍然是另线程,是不是也就是说,也就也就是说实际上他这个reactor所在的县城和我们handlener所在的县城是同一个县城,当然我用这个呢也一样,比如我来个HELLO200。回撤。看到他又转发了200 200呢,仍然。针对这个这个客户端,其实它用的也是同一个线程,是不是我们再来看第三个哈300。我们可以看到第三个客户端发送数据给这个圈的时候呢,其实呃,发送数据给这个给这个server的时候呢,你会发现它仍然用的是主线程,因此从这个图上就可以分析出来,在整个呃单react单线程运行过程中,其实我们这边就只有一个线程,大家可以想象。
09:05
那你这样子的话呢,势必造成什么样,你虽然现存数量确实是没有以前传统的IO那种方式多了,但是你这个也太少了吧。那如果说客户端很多,你势必造成这个阻塞呀,比如说你有一个客户端来了,那这进行一个read,那其他客户端再来read的时候,你是不是也先阻塞在这里,因为你只有一个线程嘛,那没办法。说这种单reactor单线程呢,它是有问题的,我们来看一下,具体来说一下。但react单线程呢,是这样子的,Select是就是我们前面所说的网络API,就那个方法,它可以实现应用程序通过一个阻塞对象监听多路连接,是不是这个没问题,React对象通过select监听客户端请求事件,收到事件后进行一个dispatch,是不是转发了呀?转发给不同的handler进行处理。如果是建立连接请求呢,就用这个accept,就是我们的接收器通过accept方法处理连接请求,然后创建一个handle对象,处理相应的这个后续的业务,只是呢,老师对应的这个对应我的那个n no方法呢,我是直接调度方法,没有去创建自己写的一个handle对象,但本质是一样的,因为它都是用一个函数或者用一个方法去处理的。
10:22
如果不是建立连接事件,则reactor会分发调用连接对应的handle来处理,说如果是数据IOIO事件的话呢,其实就已经调用我们handleler来处理了,是不是handleler他会完成的事情很多,有read、业务处理和善。你看我们在接收客户端发送的信息,实际上是在我们handler去处理的,也就是在我们read data方法去完成的,完成过后是不是我回送数据也是通过那个我们呃这写的一个叫send in for to other clients去完成这样,那结合一个实例,就是看一下服务器端用一个线程通过多路复用搞定所有IO,包括呃连,包括这个读,呃包括一个线程啊,包括它的连接创建,读写等等,这种方式呢,它的好处是编码比较简单,清晰明了。
11:17
哦,清晰比较,但是如果客户端连接数量不多,无法支撑前面的我们说的NIO群聊系统,就这个模式好的,那方案也说了,我们现在看它的缺点和优点是不是也简单,再说一下模型简单,没有多线程进程。多线程进程通讯竞争的问题,全部都在一个线程完成,性能问题只有一个线程无法发挥多核CPU的性能,就说你现在即使你你这个服务器啊,有四个四个核,因为你是单线程的那。那你这个四个四个CPU,就是你的CPU性能不能够得到嗯,充分的发挥,因为你是单线程的嘛,对不对,还有一个handle德尔在处理某个连接上业务的时候,整个进程无法处理其他连接事件,容易造成瓶颈,也就是说刚才老师说的这一点,你这种模型虽然也是艾格模型,但是如果有一个handle在进行读写。
12:10
啊,在进行读写的时候,那其他就被阻塞了,是不是这个道理好还是有问题的。好,那现在呢,我们,呃,再看它的这个还有一个缺点,可靠性,如果我们现在意外终止了,或者进入死循环,会导致整个通讯,整个系统通讯模块不可用,不能接收和处理外部消息,造成节点故障。使用场景在什么地方有可能用到呢?就是客户端的数量比较有限,不处理大并发业务,而且呢,这种业务处理比较快,因为你如果你这个业务处理就是你前面这呢,进这个业务处理很慢,你一慢那其他客户端再来也会阻塞在这个位置,因此他用这种单reactor单线程呢,它的要求就这样子的,首先你客户端数量线数量是非常限的,而且你业务处理很快。就能处理完毕,不会造成其他过端过长时间的等待。比如说像red在业务处理时间复杂度为O1的情况下,就可以使用这种单REC单线程。
13:11
就是你你这个就是数量也我的我也不是不处理这个高并发,而且呢,我业务处理也非常快,那单regard单线程还是可以使用的,对,只是它使用的这个场景非常的有限,非常有限,好同学们,那关于我们第就是。Reactor的第一种实现方式什么呀?单reactor单线程我们就说到这里。
我来说两句