netty 处理耗时任务的问题

2019-04-15 14:46:53 +08:00
 gramyang
netty 处理任务一般在 worker 线程里,对于在 netty 中如何使用线程池来处理耗时任务我觉得这篇文章说的可以: https://www.jianshu.com/p/727bbc7454dc

但是问题来了,encode 和 decode 方法算不算耗时任务?有的文章说算,有的文章说不算。我认为 encode 和 decode 姑且也应该算耗时任务吧,请教一下大家的意见
3304 次点击
所在节点    Java
10 条回复
javapythongo
2019-04-15 15:13:30 +08:00
encode 算什么耗时任务。。。又不费 cpu、又没 io
loveCoding
2019-04-15 15:18:32 +08:00
不算,但是编码 /解码有很多优化技巧在里面.
jimrok
2019-04-15 15:27:55 +08:00
netty 这种东西就是异步 IO,也就是在 decode 时,已经完成了数据的接收。decode 只是利用 cpu 做一些计算完成 byte 的转换。cpu 干这种事情是非常块的,也不需要其他子源参与。一旦你做完了 decode 得到了需要的 java 对象,那可能你会去做业务处理,例如数据库的查询,这里会阻塞 worker 线程,那么另外的连接就必须排队 decode,所以,要想让并发量高,你需要用另外的线程池去干业务的事情,或者分发给其他的服务器来做。
gramyang
2019-04-15 15:38:37 +08:00
@jimrok 顺便请教一个问题:现在有两种方式来并发处理 channelhandler,一个是用 EventExecutor ;还有一种方法是用 worker 线程的 eventloop,就是 ctx.executor。第二种方法会不会影响到 worker 线程组的接收请求的效率呢?
wucao219101
2019-04-15 15:44:11 +08:00
encode 和 decode 不算,没有 IO。
jimrok
2019-04-15 16:32:57 +08:00
@gramyang 我对 netty 不了解的。好像两者没有差别,除非是 ctx 上的 executor 被替换了默认的实现。
gz911122
2019-04-15 16:49:56 +08:00
内存操作都不算耗时任务
耗时任务一般指 io

一个简单粗暴的判断标准:任何涉及到 IO 操作的代码,都可以认为是可能造成阻塞的代码,纯粹内存操作的代码,只要执行时间没有明显超长(例如执行循环几万次的处理便可认为是执行时间超长),都可以认为是非阻塞代码。
zhaishunqi
2019-04-15 17:26:33 +08:00
@gramyang
decode 和 codec 就不说了.
两种方法个人感觉是不会有太大影响的.

Netty 的 BossGroup 和 WorkerGroup 主要用来保证系统的 IO 性能,就是所谓的 IO 线程池,只要不直接在这两个线程池里面进行耗时的操作,应该不会影响 netty 的 io 性能.

netty 启动的时候,配置了一个 BossGroup 和 WorkerGroup,伪代码如下:
```java
// 设置 NIO
serverBootstrap.channel(NioServerSocketChannel.class);
// 设置多线程模型
serverBootstrap.group(nettyConfig.getBossGroup(), nettyConfig.getWorkerGroup());
// 设置 handler 集合
serverBootstrap.childHandler(initializerFactory);
```
在增加 ctx 的时候,增加了业务线程池,如下:

```java
protected void initChannel(Channel arg0){
arg0.pipeline()
// 业务处理控制器
.addLast(businessGroup,new BusinessHandler());
}

按照你给的简书的那部分说明,找到对应源码:
```java
static void invokeChannelRead(final AbstractChannelHandlerContext next, Object msg) {
final Object m = next.pipeline.touch(ObjectUtil.checkNotNull(msg, "msg"), next);
EventExecutor executor = next.executor();
if (executor.inEventLoop()) {
next.invokeChannelRead(m);
} else {
executor.execute(new Runnable() {
public void run() {
next.invokeChannelRead(m);
}
});
}

}
```

`if (executor.inEventLoop()) {`这个分支在 addLast 时,增加了业务线程池以后,是会走下面的 else 的.

所以,我个人觉得,写在 handler 和 ctx 的线程池,实际上都是脱离了 netty 的核心 io 线程池的.并不会影响 netty 的 io 和并发吞吐量.
至于性能上的影响,在硬件配置相同的情况下.
写在 ctx 和写在 handler 的线程池的性能差别,主要看你在 handler 交给线程池前,做了什么耗时的操作没有.否则效果应该没差别.

PS:
回复不知道支持不支持 md 语法...
gramyang
2019-04-15 17:38:16 +08:00
@zhaishunqi 很精准,谢谢
runningman
2019-04-16 07:34:04 +08:00
不知道都咋玩的 可以交流交流 目前线上没问题
但是不知道是否还能优化 微信 270115861

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/555317

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX