Java中的异步IO?

Posted

技术标签:

【中文标题】Java中的异步IO?【英文标题】:Asynchronous IO in Java? 【发布时间】:2010-10-10 04:32:33 【问题描述】:

除了 java.nio 之外,java 中还有哪些异步 io(基于套接字)选项? java.nio 是否也在后台使用线程(就像我认为 .NET 的 async-socket-library 所做的那样,也许它已被更改)还是使用适当的选择调用“真正的”异步 io?

【问题讨论】:

在底层流支持的地方,.NET 使用 IO 完成端口和 ThreadPool 线程来执行回调。 Jon,底层流什么时候不支持它? 为什么不使用 java.nio 有什么具体原因吗?实际上,我正在尝试在我的工作项目中实现一些异步 i/o,而我之前没有使用过其中任何一个。因此想知道。谢谢。 我通常使用async-io.org/games.html for java,您可以获取游戏或聊天的代码示例。 【参考方案1】:

Java 的 NIO 包(从 Java6 开始)仅通过Selectors 提供对非阻塞 I/O 的支持。 Java7 有望与 NIO.2 一起发布,其中包括异步 I/O 支持。今天,你最好的选择是使用一个框架。停战提到了米娜。这里还有一些其他的。

    Grizzly。这是 Sun 的 GlassFish 服务器的 I/O 核心。 Grizzly 提供了进行异步读/写的工具(通过队列模型)。它支持 TCP 和 UDP。我在几个项目中使用过 Grizzly。这个框架有一些我喜欢和不喜欢的地方,但要详细说明这确实是另一个话题。我想说的是,启动和运行某些东西非常容易,而 Grizzly 会为您完成很多繁重的工作。 Netty。该项目来自 Mina 项目的原作者之一。我没有用过这个,所以我不知道它对异步 I/O 的支持。你应该看看。

现在,关于您关于线程的问题,NIO 选择器不使用线程进行非阻塞 I/O。在 JDK6 中,他们在 Windows 下使用 select(),在较新的 Linux 内核上使用 epoll 工具。对于异步 I/O,线程细节取决于框架。

【讨论】:

Java 的 NIO 也支持阻塞 IO。 ;) Netty 像 MINA 一样是异步和事件驱动的。在主页查看真实用户撰写的推荐和绩效报告。 :) 非阻塞IO和异步IO有什么区别? @oconnor0 内核调用在缓冲区满(写入时)和缓冲区空(读取时)下不会阻塞的非阻塞 IO,这些状态会导致相应 API 的软错误返回.然而,非阻塞IO仍然在用户空间和内核空间之间复制数据,导致不必要的额外数据复制,当涉及大量数据时,这会产生很大的开销。然后内核(可能)再次将数据复制到数据包中大小块及其周围的网络协议开销。一些网络堆栈/硬件驱动程序可能支持分散聚集以优化内核阶段,但最坏的情况是 3 个副本。 @oconnor0 Async IO 接受在用户空间和内核空间之间的数据转换期间删除额外的复制操作。这允许内核直接从用户空间访问数据。要实现这一点应用程序准备内存并向内核发布 IO 请求。控制权返回给应用程序(API 很像非阻塞)。在将来的某个时间点,内核可能会在执行 IO 时访问用户空间内存。一次done 内核通过完成处理程序向用户空间触发类似回调的信号,以通知应用程序请求的 IO 结果。【参考方案2】:

JAVA 7 到了,所以新的答案是带有 Future 类的 NIO.2。示例:

在服务器端:

final AsynchronousServerSocketChannel serverSocket=
  AsynchronousServerSocketChannel.open().bind(new InetSocketAddress("127.0.0.1", 2587)); // Listening on port 2587 for client connection
Future<AsynchronousSocketChannel> future= serverSocket.accept();
final AsynchronousSocketChannel clientSocket= future.get(); // now it's blocking, useful: future.isDone() and .isCancelled()

//Do whatever you want ..
InputStream stream = Channels.newInputStream(clientSocket) (...)

在客户端:

AsynchronousSocketChannel clientChannel = AsynchronousSocketChannel.open();
Future connected = localSocket.connect(ourServerSocketAddress);
// later: if(future.isDone())
connected.get();

//Send something
OutputStream os = Channels.newOutputStream(clientChannel );
os.write (...)

更新: 如果你可以使用actor模型,那么AKKA TCP IO会更好。

【讨论】:

未来不是真正的异步。它基于线程/信号量:docs.oracle.com/javase/7/docs/api/java/util/concurrent/… 什么是“真正的异步”? - 仅仅因为它是使用线程实现的,并不意味着它不是异步的......【参考方案3】:

关于库的另一个建议是 Naga (http://naga.googlecode.com)。它有点不像框架,更像是一个库。它试图看起来更像普通的 java 套接字,如果那是你的一杯茶。与 Grizzly、Mina 和 Netty 相比,它是极简主义的。

【讨论】:

Naga 实际上看起来像是一个非常好的异步内容包装器。 如果你只想在没有框架的情况下进行异步 Socket I/O,Naga 就是你想要的。 我好像记得有人在安卓上使用过它。 我可以确认 naga 适用于 android。我还没有用它完成一个生产质量的应用程序,但到目前为止我的所有测试都没有问题。【参考方案4】:

java.nio 只是一个包——“哑”类的集合——它本身不使用任何线程。如果使用得当,例如在Reactor design pattern 中,您可以实现正确的、完全可扩展的异步 I/O。

【讨论】:

你的回答对我来说似乎是合法的,但你能解释更多吗?请多解释一点。【参考方案5】:

如果您有兴趣将其用于 Network Stuff。一个非常好的选择是:

http://mina.apache.org/

看看那里它易于使用且非常强大。

【讨论】:

【参考方案6】:

对于最初的问题,在 Unix/Linux 系统上的 AsynchronousFileChannel 的一种情况下,实现只消耗每个 I/O 操作的线程。

【讨论】:

以上是关于Java中的异步IO?的主要内容,如果未能解决你的问题,请参考以下文章

Java中的非阻塞异步IO

Java网络编程和NIO详解5:Java 非阻塞 IO 和异步 IO

JAVA - IO模型

php协程是真正异步并且io复用的吗

oracle数据库中的异步IO

java同步非阻塞IO