参考:https://segmentfault.com/a/1190000008030772
static final EventExecutorGroup group = new DefaultEventExecutorGroup(16); ...
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("decoder", new MyProtocolDecoder());
pipeline.addLast("encoder", new MyProtocolEncoder());
// Tell the pipeline to run MyBusinessLogicHandler's event handler methods // in a different thread than an I/O thread so that the I/O thread is not blocked by // a time-consuming task. // If your business logic is fully asynchronous or finished very quickly, you don't // need to specify a group. pipeline.addLast(group, "handler", new MyBusinessLogicHandler());
其中EventExecutorGroup 就是专门来处理耗时业务的线程池。 ====================================== EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup();
这里创建了两个group, 我们提过这是boss线程组和worker线程组, 其实这两个线程组就相当于两个NioEventLoop的集合, 默认每个NioEventLoopGroup创建时, 如果不传入线程数, 会创建cpu核数*2个NioEventLoop线程,
其中boss线程通过轮询处理Server的accept事件, 而完成accept事件之后, 就会创建客户端channel, 通过一定的策略, 分发到worker线程进行处理, 而worker线程, 则主要用于处理客户端的读写事件
除了轮询事件, EventLoop线程还维护了两个队列, 一个是延迟任务队列, 另一个是普通任务队列, 在进行事件轮询的同时, 如果队列中有任务需要执行则会去执行队列中的任务
一个NioEventLoop绑定一个selector用于处理多个客户端channel, 但是一个客户端channel只能被一个NioEventLoop处理 ======================================== 一个NioEventLoop就是一个io线程,它负责读数据(异步的,系统主动通知),写数据(异步的),调用handler。
一个io线程,处理多个channel。如果某个channel的handler处理非常耗时,那么io线程就被占住了,无法及时处理其他channel了。
如果一个channel正在传送数据,另一个channel发来了完整消息,那么io线程是可以处理后者的,因为读数据是异步的,并不是io线程在那里傻等,而是系统收到数据后主动通知io线程的。 ======================================== 1.netty 中的 eventloop 就是线程的概念;
2. netty 中也没有I/O线程和用户线程的区分, 在编写netty程序时通常需要指定哪些eventloop执行哪些任务, boss eventloopgroup 对应 accept; worker eventloopgroup 对应 select/write/read 和 默认情况下的执行用户回调;
另外如果指定第三个eventloopgroup, 那么用户回调就会放在这个线程组中执行, 本意是用于执行非执行不可的用户阻塞代码, 如果非要说那么这个线程组可以对应"用户线程", 但其实并不鼓励这样写;
3. 当没有指定第三个 eventloopgroup 时, 用户编写的事件响应回调代码 就是在 worker eventloop 中执行的, 也就是说 netty 的 worker eventloop 在处理完网络请求之后, 其回调依然在同一个线程中执行, 所以根本没有所谓的资源竞争问题; ======================================== 注意,这个业务group线程池,要放到类变量里,做成static共享,别每次都new,那就死翘翘了。
一个channel,对应一个io线程,对应一个业务线程,对应一个handler。 netty都给绑定好了。
|