21 ms·
Message Passing and the Actor Model
- deckarep 9y agoI was hoping to see a mention of Pony which looks like a promising language based on the actor model.
- adamnemecek 9y agoPony does look really solid. It's still new however. Give it 4 years or so.
- krylon 9y agoWhen I took Pony for a test drive, the language itself felt pretty solid; the main obstacle was the tiny standard library. When Pony's standard library grows to a useful size, it's going to be huge. The type system is gorgeous, the documentation is pretty good, and the community is extremely friendly and helpful.
- mcguire 9y agoIt sounds like the type system is going to get more featureiferous; my understanding is that they are pushing towards actual dependent typing.
- adamnemecek 9y agoI wish I could target the browser too. Like my biggest problem is writing a front-end and backend in two languages. If I could do both in one, that would be such a killer feature.
- pmarreck 9y agoClojure and ClojureScript let you do this (albeit in Clojure)
- adamnemecek 9y agoI know. I'm rooting for Kotlin for the same reason but Pony does look super promising.
- krylon 9y agoIIRC, there is an implementation of Go that compiles to Javascript. https://github.com/gopherjs/gopherjs https://github.com/gopherjs/gopherjs I have been meaning to give it a try, but so far I have not found a good excuse to.
- Zalastax 9y agoPersonally I'm not too fond of Pony's take on the actor model. I believe it is in the models core that every actor is in total control of their own behavior, and the only interaction is via messages that can be interpreted as the receiver pleases. In Pony, it is the sender that directly commands the receiver what it will do next (via function calls/behaviors).
- mcguire 9y agoMy take is that you are looking at it the wrong way. Pony uses a single message queue for each actor (which is completely invisible at the code level) and typed messages (which syntactically look like functions). Behaviors (the message handlers) have a lot of limits on them compared to functions (like no return values), so it really is message passing. I'm not sure I really like the syntax that makes messages look like functions, though.
- Zalastax 9y ago> Pony uses a single message queue for each actor (which is completely invisible at the code level) and typed messages (which syntactically look like functions). I totally agree with this definition but believe that it leads to awkward programming. The problem stems from forcing the message queue to be FIFO, which does not always make sense. I think the Erlang style selective receive is the correct abstraction, as it avoids having to maintain a separate queue in userland. I understand why Pony didn't go down that road though, we have a lot more shared experience in type systems for function calling compared to message passing.
- mcguire 9y agoRelating Pony to some of the languages mentioned, two that seem immediately comparable are Akka and Erlang. "Akka’s receive operation defines a global message handler which doesn’t block on the receipt of no matching messages, and is instead only triggered when a matching message can be processed. It also will not leave a message in an actor’s mailbox if there is no matching pattern to handle the message. The message will simply be discarded and an event will be published to the system." "[In Erlang,] receive statements have some notion of defining acceptable messages, usually based on patterns, conditionals or types. If a message is matched, corresponding code is evaluated, but otherwise the actor simply blocks until it gets a message that it knows how to handle." Pony's message passing is syntactically similar to its methods, with a "be" (for "behavior") keyword introducing a handler rather than "fun". As a result, the message receive operation is global, like Akka, but the type system ensures that an actor cannot be sent a message it does not recognize. These are both different from Erlang, which has a local receive operation. An Erlang process, upon receiving an A message, can call another receive statement and block only looking for B messages. At that point, any incoming A messages will queue up. That has always seemed to me to be a good way to write deadlocks without realizing it. Pony is otherwise similar to a typed Erlang that compiles to machine code and doesn't (currently) have process monitoring. [:-(] There was some discussion about distributed Pony, but it has rather strong semantics for message passing, which would require a rather complex underlying protocol. [I'd rather have simple distributed messages and handle failures at the program level.] [I only have experience with Erlang and Pony; I'm hoping my description of Akka is true from the discussion in the post.]
- rurban 9y agoPony is a bit different to a typed Erlang though: * Pony has two message passing options: copy or share (by ref). Both are safe, Erlang does only copy. * Pony is non-blocking only, there are no blocking calls in any stdlib function. * Erlang supports no native threads, only green threads. So it favors IO over CPU, distributed computing on different cores is only via distributed nodes. * Pony supports native threads, but no distributed actors on different hosts yet. * Pony is massively faster, uses much less memory, and has better cleanup via a clever GC protocol.
- natdempk 9y agoI wrote this a little over a year ago, and honestly at the time I wasn't even aware of Pony. However, I am now and will likely revisit this chapter sometime this year as part of work to get this book to some finished state. Not sure whether or not Pony will make it in, but I will definitely think about it more. It is really interesting to see a new actor-model language being developed. I also see that there have been a couple of papers written about Pony, which is a good sign. Definitely on my radar for the future, but I still need to learn more about it.
- baconomatic 9y agoIs there an index to this book I'm not seeing? I see the directories, but not seeing an overall index. A bit hard to navigate.
- inetsee 9y agoIf you click on "Chapters" it takes you to a directory listing of the chapters, click on a chapter link and it takes you to another directory listing of pages. Click on a page link and it takes you to an actual chapter. It appears that the "book" still needs a fair amount of polishing to be navigable.
- baconomatic 9y agoThanks! It's just surprising when the articles are decently styled.
- haggy 9y agoSee my reply to OP but here is the GH: https://github.com/heathermiller/dist-prog-book https://github.com/heathermiller/dist-prog-book
- natdempk 9y agoYep, the book is very much far from completion. Feel free to submit issues on GitHub if you notice specific things, or just wait until later this year for all the navigation problems to be solved. :)
- haggy 9y agoThis is actually a hosted version of this GH: https://github.com/heathermiller/dist-prog-book https://github.com/heathermiller/dist-prog-book They highlight that the hosted site is far from polished but you can always host it yourself ;)
- bringtheaction 9y ago> 59 minutes read Is this actually correct? I am inclined to think not but it is difficult to judge just from scrolling through it quickly.
- haggy 9y agoIm firmly against these "X minutes to read" estimates because the amount of time it takes to read something is highly dependent on many variables (on both the reader side and article side). I would much rather have a "Short, Medium, Long, Novel" kind of scale which is simply a scaled word count of some kind.
- natdempk 9y agoAuthor here. I don't actually think so. This is likely closer to 40 minutes of reading time, and I personally don't think it is the most difficult writing to read.
- bdavisx 9y agoThe article doesn't mention [Vert.x](http://vertx.io/ http://vertx.io/), another JVM library/framework (also works outside of the JVM with Javascript for example) that is loosely based on the actor model. And now with Kotlin coroutine support, they've managed to abstract away a lot of the nodejs like callbacks that clutter up your code - you still need to be aware of what's happening wrt callbacks and such, but it makes your code a lot nicer: http://vertx.io/docs/vertx-lang-kotlin-coroutines/kotlin/#_getting_one_shot_asynchronous_results http://vertx.io/docs/vertx-lang-kotlin-coroutines/kotlin/#_g...
- natdempk 9y agoThanks for pointing this out. I've never heard of Vert.x, but I will check it out and see if it seems worth including when I revisit this chapter in the future.
- k__ 9y agoVert.x is still going? Nice! Used it back in the days for a game backend, because of the promised better-than-nodejs-performance and multithreading.
- vorg 9y agoThe docs at http://vertx.io/docs/ http://vertx.io/docs/ are available in different editions depending on what language you use with Vert.x, of which there's 7 available. Besides JavaScript and Kotlin, there's also: Java Apache Groovy Ruby Eclipse Ceylon Scala
- zmmmmm 9y agoIt's getting there but it's still not as concise as Groovy support that's been around for 5 years or more[1]. Having said that, sweet sweet (real) static typing is a huge advantage. [1] http://vertx.io/docs/vertx-core/groovy/#_the_event_bus_api http://vertx.io/docs/vertx-core/groovy/#_the_event_bus_api
- always_good 9y agoI haven't given myself the opportunity to sit down and play with an actor model. But in the meantime, despite reading literature such as this, I have trouble envisioning what it actually entails day-to-day. I think of my experience with channel-based communication in Clojure, Go, and even Rust's mpsc. And every time I feel an instant feeling of debt because I know I'm just one or two more channels away from misunderstanding the execution of my own application. Having to take out pencil and paper to reason about why messages are bottlenecking in this component or why I was wrong when I thought I knew how my application worked. For example, we ripped out all of our channels in our Go application and replaced them with a couple mutexes. When I read about actors, I get flashbacks to some of my worst struggles with channels. Where our application is split into disparate agents that everyone has to eventually map out on a whiteboard to understand even basic runtime behavior. I owe it to myself to try it out, but I can't help but be discouraged by what I think they are. Can someone clarify? What does the actor model actually mean for your day-to-day code compared to futures, for example?
- eslaught 9y agoIt's worth mentioning that this isn't the only way to do distributed programming. Dataflow programming works quite well, and the newest state of the art systems are exploring ways to generate dataflow parallelism implicitly from sequential programs. See e.g. Legion from Stanford: http://legion.stanford.edu/ http://legion.stanford.edu/ In my personal opinion, message passing is going to be considered an evolutionary dead-end in the long term, and these sorts of more intuitive programming models based on generating dataflow graphs automatically will become more dominant. Disclaimer: I work on Legion.
- mmjaa 9y ago>It's worth mentioning that this isn't the only way to do distributed programming. Its not the only way, but it is one of the oldest that is still in production. If you take a train anywhere in the Western world, your life is being protected by best x-of-x systems based around the actor model. Just sayin' ..
- krylon 9y agoIs this a good time to mention concurrentlua, a reimplementation of Erlang's concurrency model in Lua, using coroutines to model processes? https://github.com/lefcha/concurrentlua https://github.com/lefcha/concurrentlua It has not seen a lot development over the past ... couple of years, but it worked quite nicely when I last tried it.
- ninjakeyboard 9y agoI live and breathe this stuff. Started working with Elixir more recently but have worked with Akka for years. IMO BEAMVM is a great piece of technology and is worth looking at.
- fafhrd91 9y agoI'd like to mention actix, it is an actor framework for Rust language. it is single process at the moment, but distributed version is in development. https://github.com/actix/actix/ https://github.com/actix/actix/
- louwrentius 9y agoI recall that Microsoft Azure Service Fabric SDK is also based on the Actor Model.
- keithnz 9y agoMS has https://dotnet.github.io/orleans/ https://dotnet.github.io/orleans/ which is an interesting take on the actor model.
- socrates666 9y agoThis became Service Fabric
- dominotw 9y agoI have been wondering about this past couple of days. Does kafka streams make Actor Model obsolete? What can you do with actors that you can't with kafka streams if you were starting a project from ground up.
- bb01100100 9y agoThey are different worlds.. each actor would be analogous to an independent stream app; or one stream app with lots of KStream/KTable “components”, which feels like an anti-pattern.
- zmmmmm 9y agoFrom a quick skim of it I don't see any mention of the real difficulty I have encountered with the Actor model in practice: managing imbalanced actor workloads. If you consider a simple chain of actors that do some work and then send on a result to a next actor that then does some more work: A -> B -> C -> D Suppose something (anything) happens that make messages to B take slightly longer to process than the rate at which A is sending them. The result is that B's message inbox expands indefinitely. One of two things will happen depending on the queuing model: either A will block on send because B refuses to accept another message, or B will simply run out of memory from too many pending messages. This of course, is just the linear scenario. Consider a complex network where there may even be cycles (something D does could somehow indirectly result in a message coming back to A). You've essentially got a completely unstable, unpredictable system. The only way to avoid it is to ensure that every actor is massively over-resourced so that it can never fall behind on processing its messages. Of course, the second stage of this is that you start designing scalable actor "pools" where more than one actor can service messages and you can scale the size of the pool up and down. But this is at the cost of adding even more dynamic, unpredictable behaviour, and to some extent you just lost the simplicity you were trying to gain by using Actors in the first place. I'm curious if any thoughts from more experienced folks about how to handle these issues!
- ramchip 9y agoThere’s a lot of literature on this in the Erlang world. This post is a very thorough summary of the various solutions available: https://ferd.ca/handling-overload.html https://ferd.ca/handling-overload.html I don’t find that kind of fully async processing pipeline very idiomatic TBH, at least in Erlang - more typically, every request would be its own actor, and do blocking requests to other actors that own shared resources.
- zmmmmm 9y agoThank you for the insightful comments. That link looks perfect (down to the point of having a diagram with a->b->c->d just like mine!). The idea of each request being its own actor being more idiomatic is intriguing. Naively though does it really solve the problem? Don't you just end up with an overflow of actors now instead of an overflow of one actor's inbox?
- Hop_Gracer 9y agoMessage Passing along with "shared nothing" is going to be very important as all programming moves to multi-processor devices and distributed architectures. Erlang, which takes the message-passing concepts from SmallTalk with the pattern matching and error handling of Prolog, solves a lot of problems for us.
- smoyer 9y agoThe root of your book's domain (/) has the test page for tufte.css. The content itself is great!
- srazzaque 9y agoI have coded one significantly large system using Akka. I think conceptually, actors are quite simple and powerful. But in practice with Akka, I hated the fact that I couldn't just set a breakpoint and just follow a message all the way through the system via multiple F7's. Every time I got to a "send" call, I would need to find out which of the other 200 actors in the code actually dealt with that message, set another breakpoint, and keep going. Because all you have at runtime is an ActorRef which could really be anything, and all the sends are asynchronous. This was perhaps in large part due to the fact that there was a lot of Akka 101 learning going on during early development so people went a bit crazy with actorifying everything. If in doubt, create a new actor. Because erlang, resilience, Telcos use it, supervisor hierarchies, self healing, and a blog I read last week. Questioning it was a case of the emperor's new clothes. Interestingly none of the big ticket things that Akka was sold to the dev team on ever eventuated. A while into the project, my team and I were responsible for delivering a subcomponent within the system. We did so with extreme prejudice to only using actors at the very edges and entry points where a bit of asynchronicity was required. But everything within the service boundary was just plain old Java. This was the easiest to understand and maintain part of the system, as attested by another team who we handed over the entire codebase to. Guess which part had the least bugs? Most extensible? I don't know if akka has improved since then, but the debug workflow was such a departure from the normal way of doing things on the JVM it was enough to put me off and then steer clear of it in general. There are definitely other patterns and libraries I would reach for first.
- justanotheratom 9y agoI have come to realize that breakpoint style debugging should be avoided. Atleast for people working on Services. Prefer logging, or other variants like Event History, State Change history, etc.