actors conflate too much

Noel Walsh: Why I Don't Like Akka Actors.

Concurrent programming involves at least three distinct concerns: concurrency, mutual exclusion, and synchronisation. With actors the first two always come combined, and you’re left to hand-roll your own synchronisation through custom message protocols. It’s an unhappy state of affairs if you want to do something as simple as separating control of concurrency and mutual exclusion. This is not an esoteric concern...

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Actors are overly nondeterministic

In a similar vein: Actors are overly nondeterministic - Paul Chiusano.

Can you give an example of over-nondeterminism due to Actors?

Can you give an example of over-nondeterminism due to Actors?

I can.

But I won't. If you wish to comment on the linked article, read it first.

Can Actors control their resources?

Actors are designed to work in the presence of massive concurrency. Each Actor controls its use of processing and storage. (Since others might launch a denial of service attack, an exposed Actor may need distributed implementation.)

For example, a Future is an Actor that is in control of the storage and processing that it uses for a computation (which in some cases can be rather large). It is possible for a Future to respond with exceptions or even ignore messages (although this is not recommended in general). If a Future does provide the resources to entirely carry out the computation, then it can respond with an exception.

It seems to that your real criticism may be that the Actor Model is too dynamic and you would prefer something more static.

Concurrency inherently involves indeterminacy that is necessary for efficiency. (Concurrency can be exponentially faster than lambda calculus functional computation.)

Note that indeterminacy is different from nondeterminacy. See What is Computation?

PS. I apologize for not recognizing what appeared to be a bold face comment and instead turned out to be a link to your blog post.

PPS. I largely agree with the comments in the blog post of Noel Walsh at the beginning of this forum topic.

I can't read blogspot behind

I can't read blogspot behind the wall, but I'll comment anyways :) Actors necessarily jump out of the traditional computational model where we must reason about performance stochasticly. In a large and possibly widely distributed system where stochastic reasoning is a given anyways, actors might be worthwhile, but I think actors are being marketed haphazardly for other use cases where they don't make sense (I got into this argument when I was at the EPFL).

I think optimistic concurrency can perform much better, which is where I'm going with Glitch: write your code in a non-concurrent format, Glitch will execute and re-execute nodes of computation in parallel until consistency is achieved (i.e. long running operations have completed).

In cases of high traffic, optimistic concurrency can thrash

In cases of high traffic, optimistic concurrency can thrash by continually having to throw away work and start over.

Optimistic concurrency can

Optimistic concurrency can become less optimistic to escape a thrashing problem based on metrics and heuristics. Non-optimistic concurrency, OTOH, cannot generally become optimistic, due to different models for commitment.

I've found this especially nice for explicit temporal models. Every update is tagged with time, and I know that the past never depends on the future. So the heuristics are easy: dedicate more resources to computing the present than to computing the future. Similarly, it is easy to control how far into the future I speculate.

A significant advantage is that I can ensure that no part of the model falls behind. I don't run the system in lockstep, but rather as a 'flock' of agents or components with constraints on how far (temporally) the lead component gets ahead of the worst lagging component. This is augmented by implicit batching (updates relevant to a component are implicitly combined and processed together) which tends to result in the lagging components being more efficient than the leading components.

We can have very nice performance and progress properties with optimistic concurrency, without thrashing.

Can't get a purchase on the issue.

It's best to avoid solutions until you have a problem. Unless you're already swamped by an issue, don't make it worse by adding a solution more complex than your problem. Actors are a form of organized non-determinism, where this organization might be better than chaos preceding it, in some highly concurrent scenario.

I read both Chiusano's Actors are overly nondeterminstic and Walsh's Why I Don't Like Akka Actors, and I'm missing the part where either asks a direct question. In either, when you look for question mark as punctuation, it only occurs in rhetorical questions introducing what an author says next.

What's the question folks want answered? (That's my question. If I say something about actors in docs, and want to add this thread somewhere, I need to know the question. But so far I don't see it.) If some product is marketed as doing X to solve Y, just ignore it until it looks like it might address a thing you can't solve. Keep doing whatever you do now as long as it works. Let's see, I have more questions.

What is the composition problem where someone thinks agents can help? (Don't include producer-consumer scenarios, because this doesn't require agents.)

Is this what we want?

If you can't understand articles without assigning a question to them, it seems wise you should build a set of standard questions that fit most articles. Try the one suggested in the subject line.

"Actors are presented as a universal primitive for concurrency" - Welsh. "Actors are useful as a low-level concurrency primitive" - Chiusano.

Are actors what we want for a concurrency primitive?

Actors have, over the last few years, gained popularity as a "go to" solution for concurrency problems. Several implementations of actors have been developed. And there is often a degree of success when compared to shared state concurrency with mutexes. But once these people start to scale up, they suddenly need to model a bunch of queues, actor configurations; the challenge of orchestrating a few different actors-based services is quite high. The complexity builds up rapidly.

Actors are not the solution people initially think they are. Those atomic updates of a single actor don't scale or compose. Actor configurations are difficult to extend or modify without a lot of extra overhead and effort. Vocabularies tend to grow beyond a minimal set because there is no easy way to treat a sequence of two messages the same as one larger message.

Chiusano observes that large actors systems seem only marginally better than threads.

A little bit goes a long way.

I understood both articles to be pointless beyond saying actors didn't scratch the itches expected, but that's rude to say. A charitable approach is to ask what I missed. I very much appreciate you expanding a bit on detail you think salient, especially since you have expertise here. (I often find your analyses quite useful when you don't get into arguments. I wish you analyzed things more on the whole.)

For both questions, the answer is false. Walsh's point was in passive voice—without an active party—and I disagree any consensus presents actors as a good universal primitive. Pointers to such consensus might change my tune though. If Chiusano's point was about low-level use, I'd disagree because I think of actors as high level, when they bundle so many semantic details together. Maybe that's what is meant by "conflate" when you can't get individual effects without the whole package hitting you.

I guess I would not have thought actors better than threads, though they ought to scale better than native threads. As soon as you go to fibers, though, you get scaling with a thread model, and can roll your own actors as desired. (Fibers are just really hard to debug when something goes wrong.) A lot of solutions seem like the same thing, just folded differently so another set of sharp edges appear, in different places. Instead I think of actors as a kind of tactic well suited to some situations: something active that responds to messages, like a server though perhaps local, without implying specific thread mappings.

Anyway, I missed the folks (besides Hewitt of course) who are so enthusiastic about actors being better than sliced bread, so maybe I'm out of touch. Probably, since I've been in C purgatory a while.

The general pattern I expect is that everything becomes a mess as you grow and extend it, unless ruthless vigilance is devoted to re-simplifying after grafting on new features, like extra Frankenstein limbs. Code seems awfully susceptible to a virulent form of semantic entropy. A typical story goes, "I started with cool tech XYZ, and then after it leveled up and I taught it a few new moves, it went feral! I barely escaped!" Yes, that sounds right. What did you expect? It may be I'm just a pessimist.

Often, when you start applying a technique a little, you get good rewards at first, then diminishing and even negative returns when you embrace fully, once the tail starts wagging the dog. The magic line where excess begins can be hard to see; stopping when a good thing could be done still more is a safe place to hold. If you scale up to a fullscale bureaucracy, it won't treat you well.

Every good alternative to actors you describe for folks to pursue is useful and constructive. I bet few folks would mind your outlining good options every time context seems appropriate.

Edit: regarding Chiusano's concern for message buffering: Google "credit-based flow control" and look for quality material. (Fixed agent typos where actor was meant.)

it went feral! I barely escaped!

I love the "typical story" analogy.

Most people don't think about how behavior changes as systems scale. Their intuition (based only on my observations and past conversations) is that systems behave in-the-large much as they behave in-the-small. This, despite seeing counter-examples on a regular basis (like traffic or bureaucracy). Since they aren't thinking about it, they just never make the connections.

I think we should provide systems where, at least for many important properties, this intuition holds. REST has been a success in this regard. I believe that compositional properties and operators are essential for this sort of intuitive scaling. I.e. to the extent possible, important properties should be compositional properties (as opposed to being analytical, white-box).

Organizations are the way that Actors Scale

Organizations are the way that Actors scale, i.e., "compose." See Actor Model of Computation: Scalable Robust Information Systems

Discontinuity

I'm sure there are a number of abstractions that could be modeled above actors to achieve scalability and composition properties. For example, you could model pure functional programming with actors, and 'compose' actors functionally. But it always strikes me as absurd when people assert that the properties of the abstraction are therefore properties of the implementation layer. In this example, whether 'organizations' or 'functions' compose is pretty much irrelevant to the question of whether 'actors' compose.

The issue remains that users of actors model must unlearn expectations and learn a new model in order to scale, and will probably rewrite some code or require invasive modification of the libraries they use. This discontinuity is a problem, and we should be developing models that avoid common causes for it.

If actors don't scale, but organizations do, then perhaps we should abandon "actors model" and begin developing an "organizations model".

There is no "discontinuity" between Organizations and Actors

There is no "discontinuity" between Organizations and their Actor implementations. There is a natural fit between them since Organizations use messages for communication and messages are fundamental to the Actor Model.

See Actor Model of Computation: Scalable Robust Information Systems

The discontinuity regards

The discontinuity regards software design patterns in Actors Model, and how they change dramatically and pervasively when moving from small scale to large scale. This sort of discontinuity isn't unusual, but it also isn't what newcomers to Actors feel they were promised. The disillusionment can be jarring.

Whether or not Actors and Organizations can communicate naturally does not seem relevant to a discontinuity experienced by the programmer.

Ideally, we shouldn't need catastrophe theory to understand software development. PL designers should be seeking to eliminate discontinuities in the software development cycle just as much as between software components.

Large-scale organizations are made up of smaller scale ones

Large-scale organizations are made up of smaller scale ones. And communication holds organizations together. Message passing is fundamental at all scales. The communication can always be implemented using Actors.

What do you think is the discontinuity that must be experienced by programmers using Actors?

Large-scale organizations

Large-scale organizations are made up of smaller scale ones. And communication holds organizations together. Message passing is fundamental at all scales. The communication can always be implemented using Actors.

To play devil's advocate for a second, does that imply the following?

Threading is fundamental at all scales. The actors can always be implemented using threads.

Threads are not a suitable foundation for concurrency

Threads are not a suitable foundation for concurrency. They are very inelegant and their use full of pitfalls. Also they do not support support message passing as the fundamental communication mechanism.

What do you think is the

What do you think is the discontinuity that must be experienced by programmers using Actors?

In the case you describe, the switch from actors to organizations as the principle design structure. Of course, other programmers might not know your 'iOrgs' as a software pattern, so they might switch from actors to some other model. Either way, the switch is a discontinuity.

The communication can always be implemented using Actors.

And actors can always be implemented using threads. Would you therefore insist that threads scale by using organizations?

As I explained a few posts up, I find these "can be implemented in" arguments to be absurd as in "reductio ad absurdum". Stop using them.

Stacks, locks, coherent memory, etc: useful low-level mechanisms

Stacks, locks, coherent memory, etc. are very useful low-level implementation mechanisms. However they do not form a good foundation for concurrency.

There is no "switch" from Actors to Organizations. Actors are the most natural way to implement Organizations.

most natural way?

I agree that stacks, locks, etc. are poor. But I think your definition of "good" is very different than mine. For example, I prize composition, extensibility, runtime maintainability, security, simplicity, and scalability, but I do not value "unbounded indeterminacy". Based on the qualities I favor, actors are much better than locks, but much worse than dataflow concurrency.

Actors are not very elegant, and their use is full of pitfalls.

Actors are the most natural way to implement Organizations.

What does "the most natural way to implement" even mean, how would you prove it?

Is the Actor Model the same as "dataflow concurrency"?

Organizational composition, extensibility, maintainability, security, simplicity, and scalability are good.

It's too bad that you can't prove in your system that a server always responds (i.e. unbounded nondeterminism).

Is the Actor Model the same as "dataflow concurrency"? It will be interesting if you reinvent Actors :-)

you can't prove in your

you can't prove in your system that a server always responds (i.e. unbounded nondeterminism)

Indeed, I cannot. A server might diverge, or be overencumbered, or physically be disrupted or destroyed before a response can be issued. I can prove servers always respond (assuming the client is still alive) in a subset of useful cases, i.e. where I can control fan-in and co-locate the server with part of the client. I'm only interested in a response that occurs within a bounded period of time, anyway. And I want graceful degradation, fallbacks, and resilience properties to robustly adapt to and quickly recover from problems.

Your "unbounded nondeterminism" isn't useful to me, and by itself is insufficient to guarantee a response.

Organizational composition, extensibility, maintainability, security, simplicity, and scalability are good.

I suppose a lot of things seem simple and maintainable after you eschew correctness. But I don't see what's simple about negotiating inconsistencies in agreements or information. And I don't see what's maintainable about the bureaucracy and state between iOrgs.

Is the Actor Model the same as "dataflow concurrency"?

No.

The Actor Model is abstract; you can fill in details

The Actor Model is abstract; you can fill in details, e.g., co-location. But cluttering everything with irrelevant details all the time leads to confusion and disorganization.

At the appropriate level of abstraction, that a server Actor always responds can be proved in the Actor Model. The inability to reason abstractly motivated changing the CSP model from bounded nondeterminism to the unbounded nondeterminism in the Actor Model. See What is Computation? Actor Model versus Turing's Model

There is no mythical "true correctness" and there is no "absolute truth" given the presence of pervasive inconsistency in our large information systems. We can negotiate contradictions in Organizations as we find them. Denial and ridicule of pervasive inconsistency in our large information systems is both futile and self-defeating. See Formalizing common sense reasoning

How do you imagine that your "dataflow concurrency" model is different from the Actor Model other than the fact that "dataflow concurrency" (like nondeterministic Turing Machines) has bounded nondeterminism?

Collatz

At the appropriate level of abstraction, that a server Actor always responds can be proved in the Actor Model.

This is ridiculous. Let's say you have a server that, given a message containing a number and an actor to which to pass its response, responds whether Collatz conjecture holds for that number. Please prove this server always responds.

there is no "absolute truth" given the presence of pervasive inconsistency in our large information systems

I agree. But that doesn't mean we need to internalize inconsistency for small information systems. We can have consistency within bounded partitions, and we can use types that don't assume consistency relationships between data from different sources. (We could even formalize differences in beliefs via modal logic.)

How do you imagine that your "dataflow concurrency" model is different from the Actor Model

Doesn't use message passing. Tracks latency and location in the type system. Models disruption. Signals can logically coexist at a point in time. Externalizes state. Supports speculation and limited retroactive correction.

Anyhow, I won't engage you any further on actors. It isn't useful.

That a given server Actor always responds can be proved

That a given server Actor always responds can be proved in the Actor Model although it could not be proved in the original CSP model because it had bounded nondeterminism (following Dijkstra who believed that it is impossible to implement unbounded nondeterminism). See What is Computation? Actor Model versus Turing's Model

This is not say we can construct Actors that will computationally decide every mathematical conjecture (e.g. Continuum Hypothesis in a strong set theory or the Collatz conjecture).

Given the universality of the Internet, in practice all information systems applications are large information systems :-)

Unfortunately, it is not constructive to wave your hands about the following:

Tracks latency and location in the type system. Models disruption. Signals can logically coexist at a point in time. Externalizes state. Supports speculation and limited retroactive correction.

Given the universality of

Given the universality of the Internet, in practice all information systems applications are large information systems :-)

Uh, no. Even in practice, not every small information system depends on the open system called we call the Internet. Even many large information systems, e.g. sensor networks, do not have such a dependency.

it is not constructive to wave your hands about the following

Indeed. But providing a summary of differences is not the same as waving my hands. Since you asked about "your 'dataflow concurrency' model", I answered in particular about my dataflow concurrency model.

In practice, all information systems are large

Given the universality of the Internet, in practice all information systems applications are large information systems.

For example, the planetary weather sensor interpretation system is a large information system. You just have to follow the interactions :-)

Generalizing from a specific

Generalizing from a specific example isn't convincing.

Every real system is networked and consequently large

Only toy systems are small because every real system is networked and consequently large.

Classic trolling technique

Sniping answers days after the original poster has moved on. Please stop doing that.

(EDIT: Btw, I do realize the irony of the timing of my comment.)

Relevant responses should be welcome even if delayed

Some people have lives outside LtU ;-) Their relevant responses should be welcome even if delayed.

Race conditions?

How do actor systems or models avoid races. Normally an order of arrival must be specified. If this is not guaranteed by normal delays it must be enforced by the actor. What is the actual practice? I usually think about such things in terms of ladder logic.

Actors systems can express

Actors systems can express race conditions: if multiple messages are sent to an actor (even from one source) they may arrive in any order. If a developers have a problem with this (and many do) they must utilize design patterns to enforce a particular serialization.

Dale Schumacher has done some excellent work in documenting and illustrating these patterns on his blog.

Synchronize using message content as evidence.

There are still races you need to resolve. Actual practice depends on implementation. If a C coder named Jim implements actors using Wil's fiber library, idiomatic usage might depend on what Jim makes efficient and/or effective, and whether other primitives besides actors can affect state subject to races. (Naturally, Jim names his system "Jim-actors" because it has an agreeable ring to it.)

Sending a message to an actor might open a connection to a remote server, then dispatch your message inside a daemon there. An actor can't be told apart from a server in a local or remote process, unless extra guarantees are afforded to you above and beyond an API with least surface area. Quality of service in the contract might put narrower bounds on what to expect.

Dale Schumacher's Implementing Actors in Kernel looks related to your question.

When I took an operating systems class in the late 80's, part of the curriculum showed several sorts of synchronization primitives could be expressed in terms of one another, and used as alternatives in design. This included semaphores, monitors, and send/receive mailboxes rather like actors in semantics. Material like that basically explains how you structure messages to deal with races, and how this corresponds to what you get using semaphores or monitors. I rather liked the send/receive primitives myself.

Monitors are sometimes implemented using condition variables managing mutexed queues internally, which are hard to tell apart from mailboxes in their lack of ordering guarantees. In a userland fiber library, this is fairly straightforward code without a lot of mystery involved, as soon as you grasp how the scheduler involved works, which can also be simple enough to look mundane.

Variable race conditions can be syntactically eliminated

Variable race conditions can be syntactically eliminated in an Actor. Consequently, indeterminacy can be reduced to the indeterminacy in message arrival.

A list provides an ordering on its elements.

A list provides an ordering on its elements. Alternatively, elements can be numbered and resent as necessary,e.g., TCP