Skip to content

Actor-system related questions #90

Open
@uazu

Description

@uazu

Brief summary

Some stuff can't be written in a blocking model, even a non-blocking blocking model like async/await. By blocking I mean that when you do an async call, your coroutine blocks, and the called object is also blocked on that one piece of work until it returns asynchronously. An obvious example that doesn't fit this is a network stack layer where events come in from both below and above and also from timers. All these events have to be responded to immediately. Blocking (or logically blocking) just won't work.

Doing some kind of a "select" on the calling side solves the "only one outgoing call" problem, and the "being called blocks an object" (i.e. "only one incoming call") problem can probably be solved by having multiple proxy objects for your main object, so you don't block the main object. But this is all a very round-about way of getting the required behaviour.

So this is where the actor model comes in. I don't know whether you want to discuss the actor model in this review, but the subject keeps on coming back. As the author of Stakker crate, I am very happy to contribute to the discussion if it is of interest. Here are some subjects you might wish to cover in your review:

Different models of actor system in relation to async/await:

  • Very high-level actor system, i.e. used for cross-machine communication. Sits way above async/await.
  • Medium-level actor system, i.e. actors implemented immediately above async/await runtime
  • Low-level actor system, i.e. close-to-the metal actor system, sits below async/await (i.e. low-level actor system acts as an executor)

Impedance mismatch between async/await and actor model:

  • An actor can have many calls outstanding on it, and also have many calls outstanding on other actors
  • Async/await only supports one call each way without bringing in extra features
  • Means that actor systems interfacing to async/await have to deal with this impedance mismatch, i.e. either compromising the actor model (e.g. blocking the whole incoming actor queue whilst a single outgoing async/await call blocks) or adding intermediate actors that wrap an async/await object and queue the calls to that object so that other actors don't have to block

So I guess these are the questions this raises:

  • How best to handle people who come to async/await trying to solve a problem which really needs a non-blocking actor system?
  • How best to support people implementing new actor runtimes either above or below async/await?
  • How best to support interfacing between actor systems and async/await, i.e. dealing with the impedence mismatch?

For example, could we make async/await suitable for actor-like tasks? The fundamental problem is that the state self is locked during the .await. If more than one coroutine could access self at the same time (i.e. interleaved at yield points) then the problem of blocking the actor queue would be solved. (If this could be done with only static checks, i.e. no runtime RefCells or whatever, so much the better.) However maybe this is just completely incompatible with the async/await model, so it is just not possible. So an external actor system is the only way to handle these kinds of problems.

For example, stuff of interest related to async/await for my own low-level actor system (Stakker):

  • Since this plans to act as an executor to interface to the async/await ecosystem, the executor-independent interface is of great interest, e.g. common traits and other means for executor-independent async/await code to talk to executors
  • To implement actor coroutines with low overhead, it needs an 'until_next_yield lifetime in async/await in order to safely switch in and out references to self and the context. Or alternatively completion of the existing plans for Rust generators. This is allow several actor coroutines to efficiently interleave access to the same shared actor state.

Optional details

  • Which character(s) would be the best fit and why?
    Niklaus: new programmer from an unconventional background
  • What are the key points or morals to emphasize?
    • Need to guide people who have a problem to solve that isn't easily solvable with async/await.
    • Need to focus on executor-independent interop between executors and async/await to grow the executor ecosystem, e.g. to allow actor system-based executors
    • Need to consider whether it's possible to smooth the interop between actor model and async/await model

Tell me if you want me to write this up, i.e. whether this (or any parts of it) are subject areas of interest, and where in your framework for this review it should fit.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions