Java 非阻塞和异步 IO with NIO & NIO.2 (JSR203) - 反应器/前摄器实现
所以在这里我正在阅读我最喜欢的软件模式书籍之一(面向模式的软件架构 - 并发和网络对象的模式),特别是关于 Proactor/Reactor 异步 IO 模式的部分。我可以看到如何通过使用可选择的通道,我可以非常容易地实现 Reactor 风格的异步 IO 机制(并且已经这样做了)。但是,我不知道如何通过非阻塞写入来实现适当的前摄器机制。这是利用操作系统管理的非阻塞写入功能。
操作系统特定调用支持的功能,例如 GetQueuedCompletionStatus 在 win32 下。
我确实看到 Java 7 通过异步完成处理程序为 NIO 带来了一些更新(这似乎是在正确的方向)。话虽如此......鉴于缺乏对操作系统管理的异步操作(特别是异步写入)的统一跨平台支持,我假设这是一个不利用本机操作系统支持的准实现。
所以我的问题是,基于前摄器的 IO 处理是否可以在 Java 中以有利于用于特定场景的方式实现?并且,如果 Java NIO 确实支持基于前摄器的 IO 处理(在 Java 6 或 Java 7 中),是否正在利用操作系统管理的异步 IO 支持(即来自操作系统的完成回调)?此外,如果纯粹在虚拟机中实现,则性能优势非常小,以至于使用主动事件处理只能提供一种不同的(可能更简单的)构建并发网络处理软件的方法。
对于任何对主动事件处理感兴趣的人这里有一篇很好的文章,其中概述了优缺点以及与传统的每个连接线程和反应式 IO 模型的比较。
So here I am reading one of my favorite software pattern books (Pattern-Oriented Software Architecture - Patterns for Concurrent and Networked Objects), specifically the sections on Proactor/Reactor asynchronous IO patterns. I can see how by using selectable channels I can implement a Reactor style asynchronous IO mechanism quite easy (and have done so). But, I cannot see how I would implement a proper Proactor mechanism with non-blocking writes. That is taking advantage of OS managed non-blocking write functions.
Functionality supported by OS specific calls like GetQueuedCompletionStatus under win32.
I did see that Java 7 brings some updates to NIO with asynchronous completion handlers (which seems to be in the right direction). That being said... Given the lack of unified cross-platform support for OS managed async operations (specifically async write) I am assuming that this is a quassy-implementation that is not utilizing native OS support.
So my questions are, is proactor based IO handling possible in Java in such a way that it is advantageous to use for specific scenarios; and, if Java NIO does support proactor based IO handling (either in Java 6 or Java 7) is OS managed asynchronous IO support (i.e. completion callbacks from the OS) being utilized? Furthermore, if the implementation is purely in-VM are the performance benefits so little that using proactive event handling offers nothing more than a different (possibly simpler) way of constructing concurrent network handling software.
For anyone interested in proactive event handling here is a good article that outlines pros / cons and a comparison to both traditional thread-per-connection and reactive IO models.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
这其中涉及的因素有很多。我将尝试尽可能地总结我的发现(意识到关于反应器和前摄器 IO 处理实现的有用性存在争议的事实)。
Java 1.4 引入了非阻塞 IO,它与异步 IO 不同。 Java SE 7 通过 JSR203 引入了异步 IO,使“真正的”前摄器风格 IO 处理实现成为可能。
请参阅AsyncrhonousSocketChannel、AsynchronousServerSocketChannel
通读 JSR 203 规范,肯定支持使用新异步通道的完成处理程序,并且据报道正在利用本机操作系统功能,但我尚未确定到什么程度。在分析 Java 7 源代码之后我可能会跟进这个问题(除非有人抢先)。
我还没有找到有关 Java 7 中新的异步 IO 功能的任何性能比较。我确信它们将在不久的将来可用。
与往常一样,当提出解决问题的不止一种方法时,关于哪种方法更好的问题几乎总是用“取决于”来回答。主动事件处理(使用异步完成处理程序)包含在 Java 7 中,并且不能毫无目的地简单存在。对于某些应用程序,使用此类 IO 处理是有意义的。历史上,前摄器具有良好适用性的一个常见示例是在频繁发出许多短请求的 HTTP 服务器中。如需更深入的解释请阅读本文(仅用于强调 proactor 的优点,因此请尝试忽略示例代码是 C++ 的事实)。
在我看来,很明显,在许多情况下,反应器/前摄器使使用更传统方法的非常简单的设计变得复杂,而在其他更复杂的系统中,它们提供了高度的简化和灵活性。
。
。
。
顺便说一句,我强烈建议您阅读以下有关 NIO 的演示,其中提供了 NIO 与“传统”方法之间的性能比较。不过,我也建议谨慎对待所呈现的结果,因为基准测试中的 NIO 实现是基于 Java 1.4 之前的 NBIO NIO 库,而不是 1.4 中提供的 NIO 实现。
There are lots of factors involved in this one. I will try to summarize my findings as best as possible (aware of the fact that there is contention regarding the usefulness of reactor and proactor IO handling implementations).
Java 1.4 introduced non-blocking IO which is NOT the same as asynchronous IO. Java SE 7 introduces asynchronous IO with JSR203 making "true" proactor style IO handling implementations possible.
See AsyncrhonousSocketChannel, AsynchronousServerSocketChannel
Reading through the JSR 203 specs, completion handlers using new asynchronous channels are definitely supported and it is reported that native OS features are being utilized but I have not ascertained to what extent yet. I may follow up on this after an analysis of the Java 7 source (unless someone beats me to it).
I have not been able to find any performance comparisons regarding new Asynchronous IO features in Java 7. I'm sure they will become available in the near future.
As always, when presented with more than one way to tackle a problem the questions of which approach is better is almost always answered with "depends". Proactive event handling (using asynchronous completion handlers) is included with Java 7 and cannot simply exist without purpose. For certain applications, it will make sense to use such IO handling. Historically a common example given where proactor has good applicability is in a HTTP server where many short requests are issued frequently. For a deeper explanation give this a read (provided only to highlight the advantages of proactor so try to overlook the fact that example code is C++).
IMO it seems obvious that in many circumstances reactor/proactor complicate what would otherwise be a very simple design using a more traditional approach and in other more complex systems they offer a high degree of simplification and flexibility.
.
.
.
On a side note I highly recommend reading through the following presentation about NIO which offers performance comparison between NIO and the "traditional" approach. Though I would also advise caution regarding the results presented as the NIO implementation in the benchmark was based on the pre Java 1.4 NBIO NIO library and not the NIO implementation shipped in 1.4.
我会检查你是否真的需要担心阻塞写入。
读取阻塞,没有数据可读取。大多数时候都是这样。但是,当缓冲区已满时,写入会阻塞,这种情况很少发生,并且通常表示连接速度慢或消费者失败。
如果您想要非阻塞 IO,请为读取执行此操作,因此也为写入执行此操作。
注意:将阻塞 IO 与 NIO 一起使用通常更简单,并且可以执行非阻塞 NIO,除非您有 1000 个连接,否则您可能会发现增加的复杂性是不值得的。 (并且可能不是最好的选择)
I would check you really need to worry about blocking writes.
A read blocks where there is no data to read. This can be most of the time. However, a write blocks when the buffers are full, this happens very rarely and often indiciates a slow connection or a failed consumer.
If you want non-blocking IO, do it for the reads, and therefor for the writes as well.
Note: Using blocking IO with NIO is usually simpler and can out perform non-blocking NIO unless you have 1000s of connections, you are likely to find the complexity added is not worth it. (And is possibly not the best option)
这本书已经过时了,并且在任何时候都没有相关性。它源于 20 世纪 90 年代末的设计模式狂热,当时人们齐心协力将整个计算机科学简化为设计模式。
我现在的看法是NIO已经是一个框架,一个设计模式了。
With respect that book is very out of date and of dubious relevance at any date. It came out of the design pattern frenzy of the late 1990s when there was a concerted attempt to reduce the whole of computer science to design patterns.
My present view is that NIO is already a framework and a design pattern.
NIO 已经提供了反应式模式的实现(选择器),NIO2 添加了主动模式(完成处理程序)。
不要重新发明它,只是使用它,因为你无法击败它的性能 - 毕竟这是任何试图避免阻塞 I/O 的人所追求的 - 使用纯 Java 解决方案,因为你无法访问非 -底层操作系统的阻塞/异步功能。但 NIO 和 NIO2 利用了这些,这使得它们速度更快。
NIO already provides an implementation of the reactive pattern (selectors), and NIO2 adds an implementation of the proactive pattern (completion handlers).
Don't reinvent it, just use it, because you cannot beat its performance - which is what anyone trying to avoid blocking i/o is after after all - with a pure Java solution, as you don't get access to the non-blocking / asynchronous features of the underlying OS. But NIO and NIO2 make use of those, which makes them fast.