Implementing, Abstracting and Benchmarking Lightweight Threads on the JVM
blog.paralleluniverse.co
blog.paralleluniverse.co
Also: if the Google patches for the user-mode threading are adopted, will Quasar have any advantages over a JVM that uses the same syscalls? Can you explain where this would come from?
I think what you've done is genuinely cool, I'm just trying to better understand what the 10x advantage actually comes from.
If user-mode threading is adopted, Quasar could work without instrumentation, but instrumentation is a very small part of the Quasar code base.
Quasar gives you the scheduler, channels, actors, etc.
The 10x performance boost comes from the fact that there can be non-negligible latency from the time you unpark a thread to the time it starts running, while for fibers that latency is much shorter.
I guess I'm really wondering: let's say Java 9 mutexes use Linux 4's user-mode threading syscall; in that case do we need Quasar's scheduler, channels, actors etc. Or can we just use "good-old" threads and mutexes? Where would Quasar's benefits come from?
It sounds to me like the subtext to Google's patches is that rather than accepting the conventional wisdom that "threads don't scale", they've instead just fixed threads.
Trying again: Taking your example benchmark, you aren't really calling any special methods that provide any hints for cooperative threading (to my untrained eye). That's great - you've got a great abstraction. But then, what opportunities for optimization does Quasar have, that are not also available to a JVM using the magic syscall?
I'm sure there's something here, but I'd appreciate a hint!
I'm excited by the idea that threads are going to be "the right way", once these improvements make it out of the 'plex.
I also like that I can get a similar API today with Quasar :-)
Quasar doesn't just provide lightweight threads. It has rich libraries that help you make the best of them.
Can you elaborate on this a bit? Let's say I have a function called 'fetch-url' which takes a core.async channel as an argument and makes a non-blocking http request (say, using http-kit), and in the callback handler i put the result onto the channel. If I'm in some other function, in which whose body I open a core.async go block and call fetch-url from within that go block, everything is still asynchronous is it not?
What you can't do is this:
(defn foo [ch]
(go
(bar ch)))
(defn bar [ch]
(<! ch))
foo starts a go block which calls bar, which then blocks on the channel. For threads that's ok: (defn foo [ch]
(thread ; not sure about syntax here
(bar ch)))
(defn bar [ch]
(<!! ch))
So a function running in a thread can call another function that blocks. A go block can't, that's why go blocks aren't lightweight threads.BTW, in Pulsar's implementation of core.async, the first example is ok, too.
You can think of the JVM as a very good optimizing compiler that compiles your program when you load it in a way that's tailored to your environment.
Also, when it comes to concurrency support, the JVM is usually years ahead of C++ (lock-free data structures, etc.). If you're doing concurrency, the JVM is usually a better target than C++.