27

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.

Jonas
  • 121,568
  • 97
  • 310
  • 388
S73417H
  • 2,661
  • 3
  • 23
  • 37
  • 1
    If you really want to know what the implementation looks like then you can download the source code of JDK 7 and take a look yourself: http://openjdk.java.net/projects/jdk7/ – Jesper Apr 03 '11 at 11:50
  • Good point Jesper. I will put in the effort to do this soon! – S73417H Apr 05 '11 at 03:22

4 Answers4

23

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).

Is proactor based IO handling possible in Java in such a way that it is advantageous to use for specific scenarios.

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

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?

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).

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.

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.

Roman Kagan
  • 10,440
  • 26
  • 86
  • 126
S73417H
  • 2,661
  • 3
  • 23
  • 37
  • I came across this while trying to find something in java comparable to boost::asio. My take away is that nothing exists now, but something similar may be possible with Java7. – poindexter May 25 '11 at 15:12
  • 1
    As an update: Java 1.4 NIO uses on Windows select and Java 7 AIO uses on Windows IOCP, so on Windows AIO is definitely faster and more scalable. – Kr0e May 21 '14 at 18:30
10

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)

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • Agreed that for most solutions a reactor based IO handling mechanism is most appropriate. But there are circumstances where proactive IO handling is advantageous (specifically taking advantage of preemptive multi-core threading offered by the underlying OS). So I guess my question is not really relating to if proactor is necessary or if it is advantages in any specific scenario but rather can it be done successfully with Java without it being pointless. – S73417H Apr 05 '11 at 03:01
  • 1
    The main reason I suspect its not useful is that when you compare blocking NIO with non-blocking NIO, You can get significantly better performance with the blocking (one thread per connection) IO up to 1000 connections. I have not tested this on Windows, however I think you should assume that there may not be any performance improvement. – Peter Lawrey Apr 05 '11 at 08:00
2

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.

Community
  • 1
  • 1
Evgeniy Berezovsky
  • 18,571
  • 13
  • 82
  • 156
  • @EJP I totally concur with your answer, just wanted to add some flesh (that I had just discovered - so I won't forget). – Evgeniy Berezovsky May 27 '15 at 02:24
  • @EJP OT: I clicked the telekinesis.com.au link in your profile in an attempt to find out what the "musician" in your profile is all about, but... the link's dead! It lives on in the wayback machine though, and your resume told me all and more than I wanted to know. I hope the *health* section of it did not have to get revised. [wayback in 2007](http://web.archive.org/web/20091016021123/http://www.telekinesis.com.au/files/114/file/23/EJPitt.pdf) you described it as: `Excellent general health; excellent fitness; non-smoker.` If I didn't live a couple miles north in Asia, I'd love to have a beer. – Evgeniy Berezovsky May 27 '15 at 03:57
2

one of my favorite software pattern books (Pattern-Oriented Software Architecture - Patterns for Concurrent and Networked Objects)

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.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • IMO it's aged well. Non-blocking IO is something that many engineers are afraid or oblivious to. The book demonstrates a solid design for NIO in C++ that stands strong today (Boost/ACE have proactor & reactor implementations). At the risk of sounding like a pattern monger, reactor & proactor-like IO handling is something every engineer should know appreciate (especially reactor). – S73417H Apr 05 '11 at 10:55
  • @S73417H: further to this, NIO is born of select() which was born of a single thread per process. There is a school of thought nowadays that says now we have threads we don't need non-blocking/multiplexed I/O at all. And having attempted to implement a general-purpose NIO framework based on Reactor I would have to strongly disagree that it is something every engineer should know. NIO fights with Reactor so much that you don't really have a choice but to stick to NIO. The frameworks around NIO such as Mina don't act as counterexamples in my view. – user207421 Apr 05 '11 at 11:07
  • @EJP... I have to respectfully disagree with your POV. Performance aside, general purpose NIO frameworks certainly allow for better separation of concern in networking code. In my experience, if you understand and use these frameworks well, a developer can create much more understandable, flexible and testable networking applications. Further, i can't see how NIO and reactor fight with one another. I found it quite simple to implement reactor with Java NIO. Also, under conditions where thousands of concurrent network connections can be active at any one time thread pooling with reactor excels. – S73417H Apr 05 '11 at 11:48
  • 1
    @S73417H: It is simple enough to implement Reactor with NIO. What is hard is to build a general purpose framework over the top of that. My own attempts and the attempts of others such as Mina don't encourage me. Peter Lawrey has posted the results of a study, either here or in the Oracle Java forums, which refute your final point. – user207421 Apr 07 '11 at 01:23