6 ms·
Please change the title to the original, "Actors: A Model Of Concurrent Computation In Distributed Systems". I'm not normally a stickler for HN's rule about ti
by kibwen 9mo ago
Please change the title to the original, "Actors: A Model Of Concurrent Computation In Distributed Systems".
I'm not normally a stickler for HN's rule about title preservation, but in this case the "in distributed systems" part is crucial, because IMO the urge to use both the actor model (and its relative, CSP) in non-distributed systems solely in order to achieve concurrency has been a massive boondoggle and a huge dead end. Which is to say, if you're within a single process, what you want is structured concurrency ( https://vorpus.org/blog/notes-on-structured-concurrency-or-go-statement-considered-harmful/ https://vorpus.org/blog/notes-on-structured-concurrency-or-g... ), not the unstructured concurrency that is inherent to a distributed system.
- galaxyLogic 9mo ago> both the actor model (and its relative, CSP) in non-distributed systems solely in order to achieve concurrency has been a massive boondoggle and a huge dead end. Why is that so?
- lmm 9mo agoWell, lots of people have tried it and spent a lot of money on it and don't seem to have derived any benefit from doing so.
- ianbutler 9mo agoExcept Akka in Java and for the entirety of Erlang and its children Elixir and Gleam. You obviously can scale those to multiple systems, but they provide a lot of benefit in local single process scenarios too imo. Things like data pipelines, and games etc etc.
- lmm 9mo agoI've worked on a number of systems that used Akka in a non-distributed way and it was always an overengineered approach that made the system more complex for no benefit.
- ianbutler 9mo agoFair, I worked a lot on data pipelines and found the actor model worked well in that context. I particularly enjoyed it in the Elixir ecosystem where I was building on top of Broadway[0] Probably has to do with not fighting the semantics of the language. [0] https://elixir-broadway.org/ https://elixir-broadway.org/
- weatherlight 9mo agoReally depends of the ergonomics of the language. In erlang/elixir/beam langs etc, its incredibly ergonomic to write code that runs on distributed systems. you have to try really hard to do the inverse. Java's ergonomics, even with Akka, lends its self to certain design patterns that don't lend itself to writing code for distributed systems.
- katzenversteher 9mo agoIf I'm not mistaken ROOM (ObjecTime, Rational Rose RealTime) was also heavily based on it. I worked in a company that developed real time software for printing machines with it and liked it a lot.
- brabel 9mo agoActors can be made to do structured concurrency as long as you allow actors to wait for responses from other actors, and implement hierarchy so if an actor dies , its children do as well. And that’s how I use them! So I have to say the OP is just ignorant of how actors are used in practice.
- kibwen 9mo agoTo adapt the analogy from the link in the root comment, this is akin to saying "`goto` can be made to do structured programming as long as you strictly ensure that the control flow graph is reducible". Which is to say, it is a true statement that manages to miss the point: the power of both structured programming and structured concurrency comes from defining new primitives that fundamentally do the right thing and don't even give you the option to do the wrong thing, thus producing a more reliable system. There's no "as long as you...", it just works.
- lmm 9mo ago> Actors can be made to do structured concurrency as long as you allow actors to wait for responses from other actors At which point they're very much not actors any more. You've lost the deadlock avoidance, you can't do the `become`-based stuff that looks so great in small demos. At that point what are you gaining from using actors at all?
- brabel 9mo agoIf you don't think actors are useful just because you need to wait for responses, I guess you've never used actors. That's just so implausible someone would say that if they just, you know, did it.
- galaxyLogic 9mo agoIsn't this a bit theoretical since most real world systems are distributed these days, using a browser as GUI?
- sebastos 9mo agoHmm, you think? I’m currently engineering a system that uses an actor framework to describe graphs of concurrent processing. We’re going to a lot of trouble to set up a system that can inflate a description into a running pipeline, along with nesting subgraphs inside a given node. It’s all in-process though, so my ears are perking up at your comment. Would you relax your statement for cases where flexibility is important? E.g. we don’t want to write one particular arrangement of concurrent operations, but rather want to create a meta system that lets us string together arbitrary ones. Would you agree that the actor abstraction becomes useful again for such cases?
- lmm 9mo ago> we don’t want to write one particular arrangement of concurrent operations, but rather want to create a meta system that lets us string together arbitrary ones. Would you agree that the actor abstraction becomes useful again for such cases? Actors are still just too general and uncontrolled, unless you absolutely can't express the thing you want to any other way. Based on your description, have you looked at iterate-style abstractions and/or something like Haskell's Conduit? In my experience those are powerful enough to express anything you want to (including, critically, being able to write a "middle piece of a pipeline" as a reusable value), but still controlled and safe in a way that actor-based systems aren't.
- frumiousirc 9mo agoData flow graphs could arguably be called structured concurrency (granted, of nodes that resemble actors). FWIW, this has become a perfectly cromulent pattern over the decades. It allows highly concurrent computation limited only by the size and shape of the graph while allowing all the payloads to be implemented in simple single-threaded code. The flow graph pattern can also be extended to become a distributed system by having certain nodes have side-effects to transfer data to other systems running in other contexts. This extension does not need any particularly advanced design changes and most importantly, they are limited to just the "entrance" and "exit" nodes that communicate between contexts. I am curious to learn more about your system. In particular, what language or mechanism you use for the description of the graph.
- raphinou 9mo agoI'm working on an rest API server backed by a git repo. Having an actor responsible for all git operations saved me from a lot of trouble as having all git operations serialised freed me from having to prevent concurrent git operations. Using actors also simplified greatly other parts of the app.
- koakuma-chan 9mo agoSo you're just using actors to limit concurrency? Why not use a mutex?
- raphinou 9mo agoThis might be a question of personal preference. At the design stage I already find it more approachable to think in separated responsibilities, and it naturally translates to actors. Thinking about the app, it's much reasier for me to thin "send the message to the actor" than call that function that uses the necessary mutex. With mutexes, I think the separation of concerns is not as strong, and you might end up with a function taking multiples mutexes that might interfere. With the actor model, I feel there is less risk (though I'm sure this would be questioned by seasoned mutex users).
- rurban 9mo agoBecause actors were invented to overcome deadlocks caused by mutexes. See page 137. With mutexes you can forget concurrency safety.
- crustycoder 9mo agoEh? I've written a non-distributed app that uses the Actor model and it's been very successful. It concurrently collects data from hundreds of REST endpoints, a typical run may make 500,000 REST requests, with 250 actors making simultaneous requests - I've tested with 1,000 but that tends to pound the REST servers into the ground. Any failed requests are re-queued. The requests aren't independent, request type C may depend on request types A & B being completed first as it requires data from them, so there's a declarative dependency graph mechanism that does the scheduling. I started off using Akka but then the license changed and Pekko wasn't a thing yet, so I wrote my own single-process minimalist Actor framework - I only needed message queues, actor pools & supervision to handle scheduling and request failures, so that's all I wrote. It can easily handle 1m messages a second. I have no idea why that's a "huge dead end", Actors are a model that's a very close fit to my use case, why on earth wouldn't I use it? That "nurseries" link is way TL;DR but it appears to be rubbishing other options in order to promote its particular model. The level of concurrency it provides seems to be very limited and some of it is just plain wrong - "in most concurrency systems, unhandled errors in background tasks are simply discarded". Err, no. Big Rule 0: No Dogmas: Use The Right Tool For The Job.
- kibwen 9mo ago> That "nurseries" link is way TL;DR Please read and understand that blog post, I promise it's worth your time.
- crustycoder 9mo agoUm, no I won't and no it won't. I have no time for tub-thumping.
- eaurouge 9mo agoNurseries sound similar to run-till-completion schedulers [0]. > IMO the urge to use both the actor model (and its relative, CSP) in non-distributed systems solely in order to achieve concurrency has been a massive boondoggle Can't you model any concurrent non-distributed system as a concurrent distributed system? 0. https://en.wikipedia.org/wiki/Run-to-completion_scheduling https://en.wikipedia.org/wiki/Run-to-completion_scheduling
- kibwen 9mo ago> Can't you model any concurrent non-distributed system as a concurrent distributed system? Yes, in the same way that you can give up `for` loops and `while` loops and `if` statements and `switch` statements and instead write them all with `goto`, but you don't do this, and anyone advising you to do this would be written off as insane. The entire thrust of this thread is that you can have a more reliable system that is easier to reason about if you use specific constructs that each have less power, and non-distributed systems have the option to do this. Unstructured concurrency should be reserved exclusively for contexts where structured concurrency is impossible, which is what the actor model is for.
- eaurouge 9mo agoThe point I was trying to make is that you can apply the actor model to any system of isolated processes. Whether the isolated processes live on a distributed system of networked computers or on the same computer is an implementation detail. The critical issue is that each actor should own and mutate its own state. Whether all actors run on the same thread or on separate threads is also an implementation detail. For instance, AtomVM is a lightweight implementation of the Beam (actor model) that runs on microcontrollers [0]. > The entire thrust of this thread is that you can have a more reliable system that is easier to reason about if you use specific constructs that each have less power Easier to reason about, sure, fine. Your earlier comment claims the actor model is a dead end in non-distributed systems. > Unstructured concurrency should be reserved exclusively for contexts where structured concurrency is impossible, which is what the actor model is for. Results from my quick search on structured/unstructured concurrency were all references to Swift. Is this a Swift thing? In any case, the issue appears to be more about managing tasks that don't require a preemptive scheduler. As I see it, that issue appears orthogonal to distributed/non-distributed systems. 0. https://atomvm.org/ https://atomvm.org/
- logicchains 9mo agoCSP in Golang makes concurrency in it look pleasant compared to the async monstrosities I've seen in C#.
- neonsunset 9mo ago[dead]
- kibwen 9mo agoI heartily recommend reading the link the parent comment on structured concurrency. The alternatives here are not merely goroutines vs. async.
- cmrdporcupine 9mo agoI don't know if I'd apply your blanket prescription, but at some level I agree... here's where I see Actors often going wrong and substantially agree with you: state propagation / replication: I've been on more than one team that has broken their (in-process, single machine) process up into multiple "actors" (or "components" or "services") through communicating threads (usually over Rust channels) and then had a situation where they replicate some piece of state through messaging because they're been told that their system must not have global (mutable or immutable) state. But now they've just created a whole pile of inefficient boiler plate (propagating copies of effectively the same piece of global state through different services) and created a new way of having race conditions and/or just plain old stale or inconsistent data. For what are essentially ideological reasons. Every new feature in this model ends up being mostly plumbing of state replication between what are supposed to be isolated component models. The answer to me is just to establish a discipline where a given piece of data is owned for writes by one task or component, but can be freely read by any. If you truly have a stateless system or extremely clear data ownership boundaries, I can see the value of a CSP/actor approach. And in the context of Rust's borrow checker this model is fairly convenient. But it quickly becomes prone to cargo-culting and becomes a recipe for hairy, hard to maintain code. I am convinced most teams blanket applying actors would be far better suited to more tuplespaces/blackboard/Linda type model for concurrent coordination. A way of working that never caught on, but has always been attractive to me.
- kibwen 9mo agoNote that Rust supports a form of structured programming (though only via thread-based concurrency, not via async), provided by the `std::thread::scope` API: https://doc.rust-lang.org/std/thread/fn.scope.html https://doc.rust-lang.org/std/thread/fn.scope.html . The blog post above calls out an older version of this API as inspiration.
- FrustratedMonky 9mo agoTitle might have been changed for length.
- PaulHoule 9mo agoIt is endemic to the JVM world that people try various forms of snake oil concurrency inside an address space like actors and the original synchronized model when java.util.concurrent and Executors are "all you need." It was a theme in part of my career to pick up something written in Scala that used actors that (1) didn't always get the same answer and (2) didn't use all the CPU cores and struggling for days to get it working right with actors then taking 20 minutes to rewrite it using Executors and getting it to work the first time and always work thereafter.