外包网站开发 收费,律师事务所网站建设重要性,网络营销方式较为单一,链接提交入口一、Reactor三种线程模型
1.1、单线程模型 单个线程以非阻塞IO或事件IO处理所有IO事件#xff0c;包括连接、读、写、异常、关闭等等。单线程Reactor模型基于同步事件分离器来分发事件#xff0c;这个同步事件分离器#xff0c;可以看做是一个单线程的while循环。下图描述了…一、Reactor三种线程模型
1.1、单线程模型 单个线程以非阻塞IO或事件IO处理所有IO事件包括连接、读、写、异常、关闭等等。单线程Reactor模型基于同步事件分离器来分发事件这个同步事件分离器可以看做是一个单线程的while循环。下图描述了单线程模型的处理过程看起来与网上大部分资料的图片不同但本质是相同的。 注意上面的Selector之所以会有OP_ACEEPT事件是因为在单线程模型中Selector轮询的是监听套接字与已连接客户端套接字的所有IO事件。 单线程处理所有IO事件的弊端很明显。没能利用计算机CPU多核的特性一个线程某个时刻只能处理单个IO事件此时如果有其他描述符有IO事件就绪如来了一个新的连接这些IO事件将暂时得不到处理。 C框架libevent中基于event_base_loop做消息轮询使用event_base_dispatch来分发IO消息本质上是对上述模型的封装。如果不使用evthread_use_pthreads则其默认就是单线程模型处理请求。
1.2、多线程模型 一个线程/进程接收连接、一组线程/进程处理IO读写事件。也就是将accept的线程与处理读、写等IO事件的线程分离并且使用m多个线程以非阻塞IO或者事件IO来处理n个套接字的IO事件这里的n一般远大于m线程数m一般取CPU逻辑核心数的1-3倍而套接字数n则取决于请求数和进程可以打开的最大描述符个数。下图是多线程模型 可以看到这里把客户端的已连接套接字转交给某个IO线程之后由此线程轮询处理其之后的所有IO事件这实际参考了netty4的线程模型设计。实际reactor的多线程模型并不需要将已连接套接字绑定在某个线程上也可以统一放在连接池中由多个IOWork线程从池中取连接进行轮询并处理但这样会复杂很多而且容易出问题比如说不同线程从同一个channel收到了write事件这就类似惊群问题了并且多线程并发操作同一个channel后续很可能需要你将IO事件进行同步与其如此不如直接将channel绑定到一个线程让channel上触发与处理IO事件逻辑上同步。netty3中channel已连接套接字入站事件由固定线程处理出站事件由触发的线程处理netty4中修改了设计将channel绑定到固定的eventloop线程。 另外一点每个已连接套接字的IO事件由固定线程处理不代表事件也一定由此线程触发恰恰相反实际业务中读入站事件来自于客户端写数据触发而写出站事件往往由别的线程触发例如在发起一个异步mysql操作完成之后在异步回调线程中写结果数据来触发套接字的出站。
1.3、从多线程模型 一组线程/进程接收连接、一组线程/进程处理IO读写事件。它与多线程模型的主要区别在于其使用一组线程或进程在一个共享的监听套接字上accept连接。这么做的原因是为了应付单个线程/进程不足以快速处理内核中监听套接字的已连接套接字队列并发量极大的情况。如下 主从多线程模型有可能引起惊群效应。不过这个问题已经渐渐被规避内核可以保证连接只被唯一一个accept调用所获取其余对此连接的accept调用将失败。
二、Netty支持的线程模型 Netty支持单线程、多线程模型、主从多线程模型。但经本人多次测试、调试发现ServerBootstrap默认不会使用主从多线程模型。虽然server支持设置EventLoopGroup多个EventLoop。但实际对于一个本地地址IP端口进行acceptnetty只会绑定到一个EventLoop上故只会创建一个线程处理。 按本人的理解Boss EventLoopGroupMaster EventLoopGroup参数nThreads不为1的作用主要用在对共享的监听套接字或者多个本地地址监听对多个本地地址进行监听一般表示一个JVM中有多个server即有多个ServerBootStrap这时Boss EventLoopGroup可以通过共享给这多个ServerBootStrap起到作用创建多个boss/master Thread。 以下面的代码为例MASTER_THREAD_CNT为4但netty实际只会使用第一个EventLoop只会给第一个EventLoop创建线程。 调试跟踪源码可以明白netty的逻辑。 在ServerBootstrap继承的initAndRegister方法中调用MultithreadEventLoopGroup#register方法此方法调用this.next获取当前索引的下一个索引位0即是第一个EventLoop。 然后register方法进一步调用register方法在register中执行eventLoop.execute这里才会真正为监听套接字创建第一个轮询线程。 问题就在于在ServerBootstrap上调用bind方法初始化监听socket并绑定EventLoop时是调用的next方法。因此netty只会初始化第一个MasterEventLoop如果想将MasterEventLoopGroup中的每个EventLoop都初始化很显然需要重复绑定多个监听套接字或者多次绑定一个可共享的套接字。