puniverse / quasar

Fibers, Channels and Actors for the JVM
http://docs.paralleluniverse.co/quasar/
Other
4.56k stars 575 forks source link

Actor stops working when send it with messages more than its mailbox's size #283

Open jun14 opened 7 years ago

jun14 commented 7 years ago

e.g. I set the mailbox size of an actor to 20, and then send 100 messages to this actor. It stops running.

I'm wondering if it is not supported or sugguested to set the mailbox size to Actors

public class ActorTest {
    public static class SimpleMessage implements SuspendableRunnable {
        public static AtomicLong count = new AtomicLong(0L);
        private boolean last = false;

        public SimpleMessage() {
        }

        public SimpleMessage(boolean last) {
            this.last = last;
        }

        @Override
        public void run() throws SuspendExecution, InterruptedException {
            count.incrementAndGet();
        }

        public boolean isLast() {
            return last;
        }
    }

    /**
     * run this method with "-javaagent:path-to-quasar-jar.jar"
     */
    public static void main(String[] args) throws SuspendExecution, ExecutionException, InterruptedException {
        final int MAILBOX_SIZE = 20;
        Actor<SimpleMessage, Void> actor = new Actor<SimpleMessage, Void>(
                "simple actor",
                new MailboxConfig(MAILBOX_SIZE, Channels.OverflowPolicy.BLOCK)
        ) {
            @Override
            protected Void doRun() throws InterruptedException, SuspendExecution {
                while (!Strand.interrupted()) {
                    SimpleMessage message = receive();
                    if (message == null) {
                        System.out.println("received null");
                        return null;
                    }
                    try {
                        message.run();
                        if (message.isLast()) {
                            return null;
                        }
                    } catch (QueueCapacityExceededException e) {
                        throw new RuntimeException("queue's overflowed!");
                    }
                }
                return null;
            }
        };
        actor.spawn();
        for (int i = 0; i < MAILBOX_SIZE * 5; i++) {
            actor.ref().send(new SimpleMessage());
        }
        actor.ref().send(new SimpleMessage(true));
        actor.join();
        System.out.println(SimpleMessage.count.get());
    }
}
elevenxt commented 7 years ago

I have this problem too

pron commented 7 years ago

First, a general note: do not keep references directly to actors, and there is rarely a need to call Actor::ref. The suggested pattern is ActorRef<...> actor = new Actor<?>(...).spawn(). If you then need to join the actor, use LocalActor.join(actor).

Now to the matter at hand. This is certainly a documentation bug, and possibly an enhancement request. Currently (unlike what the documentation says), Quasar actors do not respect the mailbox's overflow policy, and every overflow will result in an exception being thrown in the actor by receive. It may be useful to support different policies, but there are strong reasons against it: actors are a programming paradigm designed for one purpose -- the encapsulation of runtime errors. Having a caller block because of an actor's internal behavior seems to defeat this purpose, not to mention that actors may be remote and blocking would then take on a different meaning.

So, regardless of whether we choose to support different policies that may be useful in some circumstances we haven't foreseen, it does not seem like a good idea in general to want an actor's mailbox to block the sender. If you want blocking behavior, you can use regular channels and fibers, which are designed for concurrency more than for fault tolerance.

jun14 commented 7 years ago

Big thanks for the reply. I think I'm gonna change my project to use regular channels and fibers instead.