Netty 源码阅读的思考------耗时业务到底该如何处理

本文介绍了在Netty中处理耗时任务的两种方法:在Handler中加入线程池及在Context中添加线程池,并对这两种方法进行了对比分析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1240

目录大纲:

  1. 前言
  2. 处理耗时业务的第一种方式-------handler 种加入线程池
  3. 处理耗时业务的第二种方式-------Context 中添加线程池
  4. 总结:两种方式的对比和思考

前言

熟悉 Netty 的同学都知道,不能在 Netty 中做耗时的,不可预料的操作,比如数据库,网络请求,这将会严重影响 Netty 对 Socket 的处理速度。而解决方法就是将耗时任务添加到异步线程池中。但就添加线程池这步操作来讲,可以有2种方式,而且这2种方式的区别也蛮大的。今天就好好讲一讲。

1. 处理耗时业务的第一种方式-------handler 种加入线程池

以我们之前的 Netty 的 demo 源码例子,在 channelRead 方法种进行异步:

1240

上图中的 channelRead 方法,我们模拟了一个耗时 10 秒的操作,于是,我们将这个任务提交到了一个自定义的业务线程池中,这样,就不会阻塞 Netty 的 IO 线程。

这样操作之后,整个程序的逻辑是这样的:

1240

解释一下上图,当 IO 线程轮询到一个 socket 事件,然后,IO 线程开始处理,当走到耗时 handler 的时候,将耗时任务交给业务线程池。当耗时任务执行完毕再执行 pipeline write 方法的时候(代码中使用的是 context 的 write 方法,上图画的是执行 pipeline 方法),会将任务这个任务交给 IO 线程。

下面是 write 方法的源码:

1240

当判定下个 outbound 的 executor 线程不是当前线程的时候,会将当前的工作封装成 task ,然后放入 mpsc 队列中,等待 IO 任务执行完毕后执行队列中的任务。很明显,下个任务的线程肯定是 IO 线程,因为我们没有设置。

2. 处理耗时业务的第二种方式-------Context 中添加线程池

第二种方式是 Netty 建议的方式,在添加 pipeline 中的 handler 时候,添加一个线程池:

1240

而 handler 中的代码不用做任何修改:

1240

当我们在调用 addLast 方法添加线程池后,handler 将优先使用这个线程池,如果不添加,将使用 IO 线程。

1240

所以,当走到 AbstractChannelHandlerContext 的 invokeChannelRead 方法的时候,executor.inEventLoop() 是不会通过的,因为当前线程是 IO 线程,Context(也就是 Handler) 的 executor 是业务线程,所以会异步执行,如下:

1240

这个时候,后面的整个流程就变成和第一个方式一样了。

总结: 两种方式的对比和思考

有什么区别呢?第一种方式在 handler 中添加异步,可能更加的自由,比如如果需要访问数据库,那我就异步,如果不需要,就不异步,异步会拖长接口响应时间。因为需要将任务放进 mpscTask 中。如果不凑巧,IO 时间很短,task 很多,可能一个循环下来,都没时间执行整个 task,导致响应时间达不到指标。

第二种方式是 Netty 建议的,但是,这么做会将整个 handler 都交给业务线程池。不论耗时不耗时,都加入到队列里,不够灵活。

再回顾一下我们刚开始的图吧:

1240

个人建议还是使用第一种方式,比较灵活。

转载于:https://www.cnblogs.com/stateis0/p/9062151.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值