Live data from Hacker News

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

blog.paralleluniverse.co

31–40 of 56 posts

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

#31

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

There's lots of case studies on akka in production, and people using are generally happy but also honest about bottlenecks they hit (more than a few thousand messages in message box etc

http://www.addthis.com/blog/2013/04/16/building-a-distribute...

http://marakana.com/s/akka_hammer_scala_nails,1129/index.htm...

http://corp.klout.com/blog/2012/10/scaling-the-klout-api-wit...

http://blog.kreuzverweis.com/uncategorized/moving-from-osgi-...

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

#32
post #26

Earlier quoted context omitted.

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 arra…

The skipped messages will be replayed in the "outer" receive. Obviously, selective receive has its drawbacks, but it's part of what makes Erlang simple, and it can significantly help in modeling complex state transitions.

And yes, you can assign a fiber to a ForkJoinPool of your choosing (although I'm interested in what a "dangerous task" may be).

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

#33
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…

All well and good, another measure of "lightweight" that is often quoted is a little over 300 words of overhead/erlang BEAM process and 300 bytes/akka actor, do you have comparables for Quasar?

http://www.erlang.org/doc/efficiency_guide/processes.html

http://doc.akka.io/docs/akka/snapshot/general/actor-systems.... (300 bytes: way at the bottom

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

#34
post #32

Earlier quoted context omitted.

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 arra…

The skipped messages will be replayed in the "outer" receive. Obviously, selective receive has its drawbacks, but it's part of what makes Erlang simple, and it can significantly help in modeling complex state transitions. And yes, you can assign a fiber to a ForkJoinPool of your choosing (although I'm interested in what a "dangerous task" may be).

I agree that using selective receive helps in dealing with messages that arrive out of the order of a specific state transition. Akka gives users the ability to stash messages if they want to. On the JVM, a long-running actor-based application (which is one of the reasons for using actors in the first place) can struggle with it. It's one of the reasons the original Scala Actor library is no longer in use, though there are other important reasons - such as Akka's use of ActorRef, analogous to Erlang's PIDs, which mask the instance of an actor from those who wish to communicate with it, as well as it's physical location. As you scale actors across a cluster of machines, that becomes really useful.

That's great about assigning the fiber to a FJP. A dangerous task would be anything that could take down an actor, which can be worrisome depending on what state the actor is holding. There are varying kinds of such state, including that which can easily be retrieved again from an external source, that which is "scratch" data and inconsequential if lost, and that which cannot be recovered if lost. In actor-based applications, we want to encapsulate mutable state and use message-handling single-threaded interaction to prevent concurrency issues, right? If we're going to do something that could cause the actor to fail and risk losing data, we want to export that work along with the data needed to perform the task to another actor and let IT fail rather than risk the important one. There are ways to pass such data between incarnations of an actor on the JVM by carrying it with the Exception, but it's not free and you have to know when to use it.

So a dangerous task could be asking for data across an unreliable network or non-replicated source, it could be dividing by 0, anything that could cause typing errors (even in Erlang), you name it.

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

#35
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…

http://stackoverflow.com/questions/2708033/technically-why-i...

No concrete benchmarks but everything I can find makes the same claim. A context switch in erlang is approx 20 ns, and a OS level context switch is between 1000 and 2000 ns. Mostly because it can make more assumptions about state, less processor state flushing etc.

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

#36
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…

Good question. In general the non-preemptive green-thread/fiber/lightweight-thread is a pretty well understood notion. Some OS support it, e.g. Windows supports manually scheduled fiber. However, OS support is not universal. It will take time, just like the transition from process to thread. Most supports come in the form of user-mode library since it doesn't need kernel-mode support.

Native thread needs stack which can be substantial, usually ~1M. Lightweight thread just needs a data structure to hold its data, usually hundreds of bytes to a few K. It's a factor of 1000X to 10000X.

Besides the memory advantage, lightweight threads can have performance advantage over native threads since the switching of lightweight threads on the same CPU doesn't need to do a context-switch, which can have substantial performance penalty as the L1/L2 cache and all the registers of the CPU need to be flushed and reloaded. On a multi-cpu system, memory barriers need to be crossed, cache needed to be sync'ed across CPU, and the TLB might be flushed as well, depending on how the OS implements the memory model of a thread.

Lightweight thread does require more attention from app developers since they need to worry about manually yielding now.

Java has great support on NIO which when used with lightweight threads can provide amazing scalability and performance boosts. See Netty and its friends.

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

#37
post #32

Earlier quoted context omitted.

The skipped messages will be replayed in the "outer" receive. Obviously, selective receive has its drawbacks, but it's part of what makes Erlang simple, and it can significantly help in modeling complex state transitions. And yes, you can assign a fiber to a ForkJoinPool of your choosing (although I'm interested in what a "dangerous task" may be).

I agree that using selective receive helps in dealing with messages that arrive out of the order of a specific state transition. Akka gives users the ability to stash messages if they want to. On the JVM, a long-running actor-based application (which is one of the reasons for using actors in the first place) can struggle with it. It's one of the reasons the original Scala Actor library is no longer in use, though the…

But how would a dangerous task affect the entire pool?

Also, I don't know if there should even be "important actors". Like in Erlang, we want to let it fail. Important data should be kept in a shared data structure that supports good concurrency, not in actor state. Like I said in the post, I don't think every aspect of the application should be modeled with actors.

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

#38
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…

I don't disagree with other answers, but I believe the situation can be described more easily: it isn't the same primitive, so, it isn't actually the case that someone is attempting to provide the same thing but faster: the OS is giving you "pre-emptive threads", whereas these alternatives are giving you "cooperative threads".

The argument is that for restricted use cases "cooperative threads" (which are the "dual", in a mathematical sense, to "evented" execution) are going to be faster than pre-emptive threads (which would require locks around even very short shared data usage, due to the unpredicability of the scheduler).

If the OS provided true cooperative multitasking, maybe it could do it faster, but that's something that has been pretty much decided to be a flawed OS primitive between processes ("OMG Mac OS 9 / Windows 3.1" ;P), and within a single process may as well be implemented in userland with little performance loss.

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

#39
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…

Think of threads as state machines. At the OS level, you have to track a lot more, because you have to service any process that can create a thread. Within your constrained environment, your 'thread' can be something as simple as a small data structure or record that does something when a message is passed to it or a function is called on it. The services you provide to each of your 'threads' can be lightweight, intelligently aggregated and prioritized, and can have only the memory allocated that is needed for the representation of that structure.

Think of a thread as if it were an object in C#, Java, whatever. Stuff happens to it, and it does stuff, but it's all based on propagation of state changes. It can be processing in serial, but because of the abstraction, it will appear to be concurrent, and therefore, effectively BE concurrent.

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

#40
post #33
post #21

Earlier quoted context omitted.

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…

All well and good, another measure of "lightweight" that is often quoted is a little over 300 words of overhead/erlang BEAM process and 300 bytes/akka actor, do you have comparables for Quasar? http://www.erlang.org/doc/efficiency_guide/processes.html http://doc.akka.io/docs/akka/snapshot/general/actor-systems.... (300 bytes: way at the bottom

Quasar actors consume even less memory. An idle actor occupies about 500 bytes.
Post reply on HN