The State of JRuby: 1.6 RC1, JSR 292 and NIO2 in Java 7, 1.9.2 Support
JRuby 1.6 RC1 is out and brings a long list of improvements: Charles Nutter gives an overview of JRuby 1.6, Tom Enebo shows the improved Windows support and Yoko Harada lists the changes to JRuby's embedding API
For a bit more information about the state and future of JRuby InfoQ talked to JRuby's Charles Nutter.
InfoQ: What are the big changes in JRuby 1.6?
JRuby 1.6 RC had over 2,000 commits and resolved over 260 issues. That makes JRuby 1.6 by far the largest release we've ever had.
Key features in JRuby 1.6 RC include: Ruby 1.9 compatibility - JRuby continues to track the latest version of Ruby, 1.9.2. JRuby 1.6 promises improved compatibility for most 1.9 applications including support for the new encoding APIs. Increased performance for Ruby code - JRuby 1.6 incorporates many incremental performance improvements, including faster standard libraries from Ruby 1.9, while also laying the groundwork for future development.
Improved Windows support - JRuby 1.6 delivers another round of improvements including built-in support for WIN32OLE and other compatibility fixes that make any Ruby application run as seamlessly on Windows as on any other platform.
Ruby 1.9.2 compatibility is largely complete. There are a few features that we plan to add in a follow-up release: Encoding::Converter, non-ASCII identifiers, and the 'ripper' and 'fiddle' libraries. We would like users to test JRuby in 1.9 mode to shake out remaining issues before 1.6.0 final.
InfoQ: What about Fibers?
Fibers are present and working in JRuby 1.6 RC. We will continue to work on performance enhancements in a future point release.
InfoQ: I believe some of the recent MLVM builds received Coroutine support (Lukas Stadler's work?); have you experimented with those?
We have experimented with MLVM and plan to support it in a future point release.
InfoQ: Some of the Ruby crowd and others from the Node.js community have been talking a lot about the joys of async and non-blocking I/O. What's your opinion of using blocking I/O vs non-blocking I/O?
As with all things, a mix of approaches generally works best. Asynchronous I/O allows you to punt I/O channels into a worker queue, freeing up threads and resources while that I/O channel is waiting.
For single-threaded runtimes, like MRI or V8, this is very important since there's only one thread available to do work. On multi-threaded implementations like JRuby, asynchronous I/O is still useful, but it's also possible to have many concurrent worker threads doing either blocking or non-blocking calls. The mixed approach offers the most flexibility, and also isn't hindered by system calls or libraries that don't support asynchrony.
InfoQ: JRuby seems to offer both because, unlike MRI, it has parallel threads and also NIO. Are there cases where non-blocking I/O (or async I/O with NIO 2 in Java 7) would make sense?
When implementing a server or client that must handle thousands of connections, the only option is to have a smaller pool of worker threads consuming a large number of asynchronous I/O channels. Most users won't have this use case, but when you need asynchronous channels, there's really no substitute. JRuby's I/O subsystem is built directly atop NIO, making it possible to multiplex selectable I/O channels across any number of threads. Any Ruby users interested in high-concurrency, high-load I/O really need to look at using JRuby.
InfoQ: What's your take on the recent work on Ruby 2.0, eg. Ruby Refinements? Have you tried them or experimented with implementing them in JRuby (I believe you implemented an earlier idea about selector namespaces)
Refinements are an interesting feature we hope to support once the specification is "refined" a bit more. The ability to safely namespace monkey-patches will address a common problem in the Ruby world. We have been contributing comments and prototype implementations to the Refinements discussion, and will continue to mock up sample implementations as the specification progresses.
InfoQ: It seems that Java 7 might actually become a reality sometime in 2011; are you planning to have a future JRuby version (1.7, 2.0,...) that'll use Java 7's features? If yes, which ones would be the first you'd work on (in addition to invokedynamic)?
We plan to add end-to-end support for Java 7 features. Specifically, we'd like to take heavier advantage of invokedynamic and method handles, to make it easier for the JVM to optimize Ruby code. We are also very excited about filesystem-level features in NIO2, such as support for symlinking, filesystem events, and many other low-level functions previously available only via our native POSIX extensions. NIO2 may mean JRuby can come closer to parity with native Ruby implementations when it comes to filesystem manipulation. It will also make JRuby the most reliable Ruby implementation for hooking up filesystem events across platforms. We also plan to continue supporting Java 5 and Java 6.
InfoQ: What were some of the performance improvements in JRuby 1.6, and which ones are you looking at for the next version?
The largest performance work involved reducing the overhead for Ruby calls. In JRuby 1.5 and earlier, all Ruby calls populated a thread-local data structure on every call. That data was used for things like generating backtraces, handling "super" calls, determining the current "self" and containing class, and so on. In JRuby 1.6, we have eliminated the need for this data structure for generating backtraces, which means that many Ruby methods now have nearly zero artificial call overhead. This speeds up some dispatch-heavy benchmarks many times.
We have also begun experimental work on future optimization targets. The "backtrace" work mentioned above also enables a feature called "dynopt" which uses information from JRuby's interpreter to turn dynamic calls into direct static Java calls at compile time. It is not supported in JRuby 1.6, but it can be enabled with -Xcompile.dynopt=true. On small benchmarks, it makes a tremendous performance difference. The other experimental work is on our optimizing compiler. We've continued building a new compiler and intermediate representation that will be easier to optimize before we generate JVM bytecode. This will allow us to pre-optimize Ruby code in ways that the JVM might not figure out. We'll continue to work on both features for future JRuby releases.
Martin Thompson Jul 27, 2014