如何在Netty通道处理程序中安全地执行阻止操作?

Ste*_*ins 7 java multithreading asynchronous nio netty

我正在构建一个基于Netty的小型应用程序,该应用程序通过套接字连接(即telnet / ssh)执行I / O操作。我正在用Netty的ServerBootstrap类启动我的套接字服务器,给它:

  1. 类型的事件循环NioEventLoopGroup(即不应接受阻塞操作的共享线程池)。

  2. 一个类型的通道NioServerSocketChannel(我相信这必须与上面的#1相对应)。

  3. 一个非常简单的管道,带有可扩展的通道处理程序ChannelInboundHandlerAdapter

channelRead(...)每当从客户端套接字连接接收到命令字符串时,都会调用我的处理程序的方法,并根据命令返回一些响应字符串。

对于不涉及阻塞操作的命令,一切都很好。但是,有些命令现在需要从数据库读取或写入。这些JDBC调用本质上将受到阻塞……尽管我可以使用CompletableFuture(或其他方法)在单独的线程中处理它们。

但是,即使我通过在单独的线程中执行阻止操作来实现“自己拥有自己的异步”,我也不知道如何将那些产生的线程的结果重新连接回主线程中的Netty通道处理程序。

我看到ChannelHandlerContext该类具有以下方法:

ChannelFuture writeAndFlush(Object msg, ChannelPromise promise);

...作为我目前正在使用的替代方案:

ChannelFuture writeAndFlush(Object msg);

但是我找不到任何文档或指南(甚至是有用的Javadocs)来解释ChannelPromise在这种用例中如何使用这种类型。顾名思义,它可能相关,但可能无关。毕竟,该writeAndFlush方法仍然将传出消息作为它的第一个参数...因此,如果您需要将其结果保存在第一个参数中,那么将阻塞操作填充到“承诺”第二个参数中有什么好处参数?

这里正确的路是什么?有什么方法可以处理单独线程中的阻塞操作,以使Netty NioEventLoopGroup不会阻塞?还是这不是Netty的工作原理,如果需要支持阻塞,应该使用不同的事件循环实现(即为每个客户端套接字连接生成一个单独的线程)。

Mad*_*apu 5

如果Netty中的操作需要较长的时间才能完成或正在阻塞,则建议在中执行该操作,handler that uses a separate ExecutorGroup以免主EventLoop线程被阻塞。

您可以在管道创建期间指定它。

引用从ChannelPipeline javadoc使用执行程序组进行数据库操作的示例

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());
Run Code Online (Sandbox Code Playgroud)