Lightweight threads in Akka
Asked Answered
I

2

9

I recently read about Quasar which provides "lightweight" / Go-like "user mode" threads to the JVM (it also has an Erlang inspired Actor system like Akka but that's not the main question)

For example:

package jmodern;

import co.paralleluniverse.fibers.Fiber;
import co.paralleluniverse.strands.Strand;
import co.paralleluniverse.strands.channels.Channel;
import co.paralleluniverse.strands.channels.Channels;

public class Main {
    public static void main(String[] args) throws Exception {
        final Channel<Integer> ch = Channels.newChannel(0);

        new Fiber<Void>(() -> {
            for (int i = 0; i < 10; i++) {
                Strand.sleep(100);
                ch.send(i);
            }
            ch.close();
        }).start();

        new Fiber<Void>(() -> {
            Integer x;
            while((x = ch.receive()) != null)
                System.out.println("--> " + x);
        }).start().join(); // join waits for this fiber to finish
    }
}

As far as I understand the code above doesn't spawn any JVM / Kernel threads, all is done in user mode threads (or so they claim) which is supposed to be cheaper (just like Go co-routines if I understood correctly)

My question is this - as far as I understand, in Akka, everything is still based on JVM Threads which is most of the time maps to native OS kernel threads (e.g. pthreads in POSIX systems), e.g. to the best of my understanding there are no user-mode threads / go like co-routines / lightweight threads in Akka, did I understand correctly?

If so, then do you know if it's a design choice? or there is a plan for go-like lightweight threads in Akka in the future?

My understanding is that if you have a million Actors but most of them are blocking then Akka can handle it with much less physical threads, but if most of them are non blocking and you still need some responsiveness from the system (e.g. service million of small requests for streaming some data) then I can see the benefits of a user mode threading implementation, which can allow many more "threads" to be alive with a lower cost of creating switching and terminating (of course the only benefit is evenly dividing responsiveness for many clients, but responsiveness is still important)

Is my understanding correct more or less? please correct me if I'm wrong.

*I might be completely confusing user-mode threads with go/co-routines and lightweight threads, the question above relies on my poor understanding that they are all one of the same.

Inferential answered 1/5, 2014 at 19:34 Comment(3)
This is what I remember from my experience with Python. And it is not a direct answer, but it might be useful. Both user/lightweight threads and actual system threads have their uses. It boils down to this, both provide concurrency but only system threads provide parallelism. So if you're doing heavy computations you will not get any boost from using user threads, but you will from system threads. In a different situation, where you only have one CPU core and you want a server, using user threads is the only solution.Firsthand
Yes, this is what I understand as well, e.g. user threads are good only for providing "good utilization" of CPU e.g. switching between 2 user threads that sometimes do blocking IO is cheaper than using full blown thread. you don't get parallelism but you do get better utilization of the CPU if I understood correctlyInferential
Please have a look at my answer, it can be helpful: #29681218Lasala
S
9

Akka is a very flexible library and it allows you to schedule actors using (essentially it boils down to that through a chain of traits) a simple trait ExecutionContext, which, as you can see, accepts Runnables and somehow executes them. So, as far as I can see, it is likely that it is possible to write a binding to something like Quasar and use it as a "backend" for Akka actors.

However, Quasar and similar libraries are likely to provide special utilities for communication between fibers. I also don't know how they would handle blocking tasks like I/O, probably they would have a mechanism for that too. I'm not sure if Akka will be able to run correctly over green threads because of this. Quasar also seems to rely on bytecode instrumentation, and this is a rather advanced technique which can have a lot of implications preventing it from backing Akka.

However, you shouldn't really worry about lightweightness of threads when using Akka actors. In fact, Akka is perfectly able to create millions of actors on the single system (see here), and all these actors will work just fine.

This is achieved via clever scheduling over special kinds of thread pools, like fork-join thread pool. This means that unless actors are blocked on some long-running computation they can run over a number of threads significantly less than the number of these actors. For example, you can create a thread pool which will use at most 8 threads (one for each core of 8-core processor), and all actors activities will be scheduled on these threads.

Akka flexibility allows you to configure exact dispatcher to use for specific actors, if it is needed. You can create dedicated dispatchers for actors which stay in long-running tasks, like database access. See here for more information.

So, in short, no, you don't need userland threads for actors, because actors don't map one-to-one to native threads (unless you force them to, that is, but this should be avoided at all costs).

Schnabel answered 1/5, 2014 at 20:40 Comment(3)
Fewer threads – fewer context switches given the same latency. So, in short, yes, you might consider using userland threads, if you can.Pretorius
"This is achieved via clever scheduling over special kinds of thread pools" <- Where would I get more information about how this is actually done (in the most simplest form)?Sarchet
@Sarchet I'm not sure about the most simplest form, but you can start on reading about dispatchers in the akka docs and then continue directly to the documentation for the fork-join thread pool. You can also google about fork-join thread pools, you will find a lot of tutorials and explanations.Schnabel
L
3

Akka actors are essentially asynchronous and that's why you can have a lot of them, while Quasar actors (yes, Quasar offers an actors implementation too), that are very close to Erlang's, are synchronous or blocking but they use fibers rather than Java (i.e. at present OS) threads, so still you can have a lot of them with the same performance as async but a programming style just as straightforward as when using regular threads and blocking calls.

I/O is handled through integrations: Quasar includes a framework to convert both async and sync APIs into fiber-blocking and Comsat include many such integrationsalready (one with Java NIO is included in Quasar directly).

My reply to another question contains further info.

Lasala answered 25/10, 2015 at 10:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.