Proto Actor – Fast distributed actors for Golang and C#
proto.actor
proto.actor
Actor-based approaches with hundreds of thousands of actors are really amazing, powerful and often simpler than equivalent channel based systems, conceptually. But they require special GC considerations to be made "efficient" of a really high level of mechanical sympathy to make sure you aren't creating pathologically bad situations for the garbage collector.
Take one or two features from Erlang into another language, and you have meh.
But what doesn't work is trying to slavishly copy the Erlang/Pony style without those considerations.
If that's what your domain space needs, use the BEAM and find a way to talk to it for the parts that you can't move to Erlang.
I say this as an big fan of Erlang, truth is, sometimes you just have to accept that your job is to write a python/Django backend without a line of JavaScript in order to serve as a line of business app, and if the load gets bigger, you just throw another server at it.
That said, erlang is great, elixir is awesome, and both are 100% worth every developers time to learn.
Can I be honest? As a language, Erlang kinda is a cube of frozen barf. It's not messy, but it's certainly not delicious. I do not "love it." I think most people sort of work around this; OTP is so good you put up with a kinda ugly syntactic substrate. Ideas good, array syntax bad, etc.
>powerful and often simpler than equivalent channel based systems, conceptually
Without true experience with any of agents/channels, what make it simpler? I read the GO and compare with Actors in F# or Erlang and for me it easier to understand channels. Mainly because are typed on the data.
I have not experience in this area.
But is the same if untyped. Because the internal schema is changed?
I suppose?
> Without true experience with any of agents/channels, what make it simpler?
If you are very clear about not retaining references to things you ship to another actor, Erlang is marvelously concurrent without any of the usual considerations for shared memory or functional programming we have to make. You can confidently manipulate and mutate variables in your actor scope because your actor is single threaded and OTP makes async-with-response calls trivial to mix in with this when you want function semantics.
Actor based systems give you a place to put sequential mutation code and a clear, clean, scalable way to define parallel operations. Channels really... well they give you this blunt force instrument to export data but you end up implementing actor-like management every time they're invoked if you're doing any sort of fan-out anyways.
I imagine this is the reason for build a custom-made VM, and not be a good fit inside Java/.NET?
It's great to see more actor runtimes on the rise. Also interesting to see the actor model implemented in Go, which follows more of a pi calculus design with its channels. With an actor design, the software architecture shifts towards the endpoints of the communication.
CAF targets the performance-sensitive C++ community, so sending a message in the same process only costs a single hardware-support CAS operation. We found this scales very well. No GC other than reference counting.
For those interested in learning more about actors in the C++ ecosystem, I recently gave a talk about CAF and some performance comparisons to other frameworks in various scenarios: http://matthias.vallentin.net/slides/caf-rise.pdf
e.g. see this CLI tool for managing proto.actor systems live: https://asciinema.org/a/a1b18jiv703e6eog1o2b7domi
You will be able to send messages to actors, connect to remote nodes etc.
There are also very fine-grained interception points allowing us to plug in things like zipkin.io w/o altering how the user writes their code.
Akka.NET is production ready and has a huge community. has commercial support etc. There are however a fair number of design issues that I dislike personally which led me to start Proto.Actor
The .NET implementation of proto.actor is in alpha version right now. We are building and stabilizing the Go version first, which already is used in major production systems.
Serialization and the concept of the ActorRef. They both go hand in hand.
in Akka/NET, ActorRefs are contextual, they belong to a given ActorSystem.
This means that when they are serialized, the serializer needs to be able to know how to transfer and rebind this context on serialization and deserialization. To make it more complex, ActorRefs can be embedded in other messages. There are a few other primitives also that are contextual and serialized. This limits the options you have in terms of serializers. It also puts a massive tax on the framework in terms of maintenance.
ActorRefs are also "resolved" when deserialized, so the deserializing system has to figure out which actor is targeted. This lookup is slow due to parsing and scanning of actors and their children.
This makes network communication speed suffer _a lot_.
The configuration DSL HOCON is also tightly integrated with the entire infrastructure, making it hard to reason about what is going on and what parts of the config the current piece of code actually sees. Akka/NET also lacks good interception points, its hard to hook into actors and monitor them.
There are just too many moving parts for my own liking. I did blog about some of the problem areas in my POV about a year ago: https://rogerjohansson.blog/2016/03/13/random-things-learned...
So the issues are really both on a performance level and at a maintenance level.
The mindset in Akka.NET have been more "lets build everything ourselves from scratch to match the JVM" and in proto.actor "lets re-use proven tech and glue them together, with minimal code"
func actor_foo(things) error {
set_up_stuff()
defer clean_up_stuff()
for {
select {
case msg := <-messages:
switch msg.(type) {
case *Bla:
}
case <- other_messages:
case <- errors:
case <- signals:
return nil
}
}
}
I recognize there is more to the actor model than just message loops, but I found that an explicit for-select-switch results in better overall readability.If parent need a "done" channel, it passes it in and "actor" closes it on its way out.
Cleanup usually "signals" children and waits for them to be "done".
Sometimes "done" is just signalled by the goroutine returning and it is wrapped in parent somehow.
But every time I try to formalize it into some "framework" my abstraction fails.