Live data from Hacker News

Show HN: Lightweight Threads, Channels and Actors for the JVM

blog.paralleluniverse.co

21–30 of 56 posts

Re: Show HN: Lightweight Threads, Channels and Actors for the JVM

#21
post #16

Earlier quoted context omitted.

Elsewhere in this discussion- Jetlang doesn't offer lightweight-threads. It uses an event-driven processing of messages (like Akka), so fibers can't block and you can't do selective receives. https://news.ycombinator.com/item?id=5646097 Akka relies on operating system threads- when you block in Akka, you block in real life.

According to this Akka document - http://doc.akka.io/docs/akka/1.3.1/scala/dispatchers.html "Akka supports dispatchers for both event-driven lightweight threads, allowing creation of millions of threads on a single workstation, and thread-based Actors, where each dispatcher is bound to a dedicated OS thread." I also, would like to see the perceived shortcomings of Akka, since lightweight threads can't be the problem.

Akka calls them lightweight threads, but they really aren't as they can't be blocked. In short - they're not implemented as continuations.

Basing the implementation on real lightweight threads gives you selective receive and other goodies mentioned in the post, while maintaining the API simple. I think Quasar/Pulsar are much simpler than Akka, and they will stay simpler for said reason.

All in all, Akka feels a lot more complicated than Erlang. Also, Scala isn't everyone's cup of tea, and Akka doesn't mesh well with Clojure.

Quasar tries to join the power of Erlang with the power of the JVM. Pulsar tries to join the beauty and elegance of Erlang with the beauty and elegance of Clojure.

Re: Show HN: Lightweight Threads, Channels and Actors for the JVM

#22
Selective Receive sounds great. Any idea how to handle messages that continue to pile up behind your actor when they're never handled? Do they get culled somehow after a period of time? If not, how do you handle the inherent memory leaking where every actor piles up messages that were never handled, and wastes processing time by replaying them every time you do handle a message? Works okay when you have lightweight processes that are completely independent, like in Erlang - on a monolithic process like the JVM, not so much.

Also, with the lightweight threads using CPS - how do you prevent the kernel from deciding to do some housekeeping tasks on your core? Using APIC or something in Linux to assign the JVM process exclusively to cores so you're guaranteed no interruptions? User-level hardware affinity is not exactly the JVM's strong point.

Re: Show HN: Lightweight Threads, Channels and Actors for the JVM

#24
Ignorant newbie here, but would love to hear views on this: I always treat with great skepticism claims that you can implement an inherent operating system function (eg: threads) on top of said operating system more efficiently than can be done by the OS itself. Usually it means the implementor simply didn't understand the next level down (eg: how the kernel works) and therefore couldn't tune it to their needs. But they understand the next level up extremely well. And there's nothing wrong with this, especially since one is platform independent and the other is (usually) very tied to specifics.

The one thing that seems evident to me is that native threads, in Java, all require a stack frame and this consumes memory. At some point millions of threads will, if nothing else, require gigabytes of memory for stack space. However in this era when the kind of computers that are likely to run these applications can easily have hundreds of GB of memory, I'm not even sure if that is an inherent limitation.

So to tldr; - can someone give me the insight, what is it that makes this more efficient at the language layer than the kernel layer? Why can a high level language magically scale to millions of threads and the OS can not? What is it that allows this?

Re: Show HN: Lightweight Threads, Channels and Actors for the JVM

#25
post #21

Earlier quoted context omitted.

According to this Akka document - http://doc.akka.io/docs/akka/1.3.1/scala/dispatchers.html "Akka supports dispatchers for both event-driven lightweight threads, allowing creation of millions of threads on a single workstation, and thread-based Actors, where each dispatcher is bound to a dedicated OS thread." I also, would like to see the perceived shortcomings of Akka, since lightweight threads can't be the problem.

Akka calls them lightweight threads, but they really aren't as they can't be blocked. In short - they're not implemented as continuations. Basing the implementation on real lightweight threads gives you selective receive and other goodies mentioned in the post, while maintaining the API simple. I think Quasar/Pulsar are much simpler than Akka, and they will stay simpler for said reason. All in all, Akka feels a lot m…

Akka works fine from Java and Clojure (http://doc.akka.io/japi/akka/2.1.2/ | https://github.com/jasongustafson/akka-clojure)

Re: Show HN: Lightweight Threads, Channels and Actors for the JVM

#26

Selective Receive sounds great. Any idea how to handle messages that continue to pile up behind your actor when they're never handled? Do they get culled somehow after a period of time? If not, how do you handle the inherent memory leaking where every actor piles up messages that were never handled, and wastes processing time by replaying them every time you do handle a message? Works okay when you have lightweight p…

Regarding selective receive: the messages aren't replayed whenever a new message comes along. The receive operation keeps a pointer into the queue to the last message scanned. Whenever the inner receive returns, the outer receive continues to scan the queue wherever it left off. Now, in general it's a good idea to use bounded queues so messages don't pile up indefinitely. When the queue overflows, the queue's owning actor (the receiver) will get an exception. When it gets the exception, it will either want to terminate or flush the queue.

If you need affinity, I recommend Peter Lawrey's Java-Thread-Affinity library (https://github.com/peter-lawrey/Java-Thread-Affinity).

Re: Show HN: Lightweight Threads, Channels and Actors for the JVM

#27
post #24

Ignorant newbie here, but would love to hear views on this: I always treat with great skepticism claims that you can implement an inherent operating system function (eg: threads) on top of said operating system more efficiently than can be done by the OS itself. Usually it means the implementor simply didn't understand the next level down (eg: how the kernel works) and therefore couldn't tune it to their needs. But t…

In general, higher levels have more knowledge of the specific problem domain, and can therefore make more assumptions, while the kernel has to cater to all needs.

In this particular case the fork/join scheduler supports the constant creation/destruction of new fibers, and of one fiber constantly "waking-up" other blocked fibers. Even if OS task switching is good, OS threads weren't meant to be short-lived and quick to start.

That said, OS task-switching can be quite good. That's why I've left the option of running Quasar actors tied to a thread rather than a fiber. I've tried to hide the implementation details as much as possible from the user of the API.

Re: Show HN: Lightweight Threads, Channels and Actors for the JVM

#29
post #28

Looks cool, but what's the distribution story? I'm not sure I understand the comparisons to Akka without one.

We intend to provide distribution on top of Galaxy ( http://puniverse.github.io/galaxy/ ).

Is Pulsar + Galaxy + Zookeeper + presumably some new code/project still simpler than Akka? It sounds kind of complicated.

Re: Show HN: Lightweight Threads, Channels and Actors for the JVM

#30
post #26

Selective Receive sounds great. Any idea how to handle messages that continue to pile up behind your actor when they're never handled? Do they get culled somehow after a period of time? If not, how do you handle the inherent memory leaking where every actor piles up messages that were never handled, and wastes processing time by replaying them every time you do handle a message? Works okay when you have lightweight p…

Regarding selective receive: the messages aren't replayed whenever a new message comes along. The receive operation keeps a pointer into the queue to the last message scanned. Whenever the inner receive returns, the outer receive continues to scan the queue wherever it left off. Now, in general it's a good idea to use bounded queues so messages don't pile up indefinitely. When the queue overflows, the queue's owning…

If you're not replaying unhandled messages, you're not doing selective receive. To quote LYSEFGG, "Ignoring some messages to handle them later in the manner described above is the essence of selective receives" (http://learnyousomeerlang.com/more-on-multiprocessing). Erlang also doesn't limit mailbox size, so while it's great that you offer bound mailboxes (which is also great for performance since they can be array-based), it's not quite as flexible. And since you haven't begun to implement supervision or OTP, you'll have to handle failure as well when you break your bounds.

I'm a big fan of Martin Thompson's Mechanical Sympathy concepts, and I'm very intrigued in Peter Lawrey's work with Chronicle as well. That said, that hardware affinity library relies on native C code, and you better know what you're doing when you put it in. The topology of the CPUs and locality mean you have to be smart in your assignments, lest you end up message passing via QPI/Hypertransport between sockets at a latency of ~20ns/message. Point being, either be intimately familiar with your box and reconfigure for each kind on which you deploy, don't ever use a hypervisor, or pin and pray.

Are you able to introduce bulkheads and failure zones with your lightweight threads via CPS? If not, isolation of dangerous tasks on a thread that could impact other actors could be an issue. Akka does this by allowing you to specify what thread pool (preferrably forkjoin-based) you want to use for each actor.

Look, this is neat stuff you're doing. I'm not concerned that you don't like Scala, but Akka can be used from Java as well so that's a non-argument. It's merely another approach. And while you certainly CAN block in an Akka application, there are plenty of tools for asynchronous coding in Scala (Futures, Async) to help you avoid that and only block when you absolutely must.

Post reply on HN