-
Notifications
You must be signed in to change notification settings - Fork 23
Idea: allow tell
to yield execution context
#77
Comments
Yes, I think it's a pretty interesting idea! "but..." we can't do that in Scala without macros, and we do not want macros in core Akka. It would also not be possible to do for Java, which is usually a requirement for all Akka features. |
Yes I've been actually pondering this conceptual possibility recently... The problem is that then we allow actors to be able to lock up. Though if we made them only suspend if they I think this is a very interesting area to consider but likely not in Akka Actors hmm... |
Hi @Horusiath, Since Akka embraces distributed computing I don't think this proposal will work out in practice since at-most-once delivery makes it impossible. The feature will not be virtually-zero cost since there will be the cost of tracking mailbox state and mutual exclusion, cost of creating continuations, cost of managing recursion, cost of clearing/setting/restoring contextual information etc). There's also the problem of serializing execution since an actor wouldn't be able to send messages and have them being processed in parallel. Cheers, |
@viktorklang that's why I wrote "virtually" ;) I think, that empty-and-idle check can be done directly on recipient's status flags with a single CAS operation + comparison. Continuation indeed has its weight (in .NET I imagine this could be elided by using value types for optimistic cases), but this is something that should be measured. Regarding parallel execution: this can be tuned via dispatchers or potentially can even depend on what you want to do with tell's result - if it's lazily evaluated: Behaviors.receive { (ctx, msg) =>
for {
val awaiters = recipients.map(_ ! Request)
// bellow free current thread until all awaiters complete
// (they can be processed in parallel without execution context propagation)
_ <- whenAll awaiters
} yield Behaviors.same
} This is a common pattern for parallelism in .NET |
That one is oversimplified though (dangerously misleading if it existed!). |
@ktoso not necessarily - "awaiter completion" doesn't has to mean message processing. I'm still describing it as a process of putting the message on actor's mailbox. |
@Horusiath I'm not sure I follow. What semantic value does "putting it on the actor's mailbox" have? I'm not really clear on what problem we're trying to solve. Could we perhaps start over by talking about use-cases? |
Sorry, maybe I'm interchanging between too many cases.
This is related to the situation when we have actors with full, bounded mailbox. Currently in that situation we can do one of two things:
With awaitable approach, we can also stop executing current actor's code (just leave awaiter so we can return to it later) without dropping messages (they would stay inside awaiter, until mailbox will be emptied) or thread blocking. Additionally if receiver was not processing any message atm. we could continue execution on its side, therefore dequeueing full mailbox. |
I was thinking about something like this, can Akka suspending the current Actor, and only continues processing after the
If the actor can yield and will not process any further messages inside the mailbox, then we can implement some more interesting things. |
The idea presented here is to enhance actor-to-actor communication with
!
/tell
by adding to it an optional mechanism for yielding current execution context or letting it to continue execution in recipient actor.It could be expressed by a return value of tell, which is able to suspend current execution on demand and would be completed, once a message has successfully received (not processed!) by the recipient's mailbox (in case of remote communication, that "recipient" could be an endpoint writer).
In C# we have async/await mechanism, which allows us to build an asynchronous state machines. Moreover it allows users to specify both custom state machine builders and awaitable continuations:
For motivation I want to cover 2 cases.
1. Passing message to an empty mailbox of idle actor
First case is when an actor A tells message M to another actor B living on the same process. In this case we could reduce an overhead of communication via mailboxes using following approach:
_ <- B ! M
immediatelly suspends execution on A, and continues processing messageM
directly on actorB
.In this case we don't even need to put message to the
B
's mailbox or schedule it via message dispatcher. Instead we could process it immediatelly. This means, that the cost of sending a message between two local actors is virtually zero.This could be further chained (as
B
may want to send some message toC
etc.). Latency for such cases would be greatly improved. Eventually this would end, causing a suspended continuations to rollback to an original actor, letting it continue it's execution. If such chain is too deep, an Erlang style reductions could be applied - which the difference that reductions work on!
instead of every single function call.Further idea
With the right approach this could be evaluated further into situation when we could make such message propagation via
ask
/?
as well - in that case we in happy path scenarios we could also reduceask
to be almost an equivalent of function call. However this would probably require that reply is the last statement of actor processing:2. Passing message to actor with full mailbox
On the other side, if we use actors with bounded mailboxes and we want to pass message to an actor with full mailbox, we can use tell continuation to suspend current execution in order to avoid blocking, and to apply backpressure. Example:
_ <- B ! M
immediatelly suspends execution on A, and continues processing on B in order to free its mailbox first.A similar approach is used in Pony language to apply backpressure to actors.
The text was updated successfully, but these errors were encountered: