This page may be out of date. Submit any pending changes before refreshing this page.
Hide this message.
Quora uses cookies to improve your experience. Read more

How are Akka actors different from Go channels? How are two related to each other?

4 Answers
Roland Kuhn has given a good description of Akka actors and Go channels/goroutines. I have worked extensively with both and would like to offer a few additional comments.

Firstly, it is important to stress that CSP allows rendezvous-based synchronisation between goroutines using channels, and channels can optionally include buffering.

When one goroutine attempts to send on an unbuffered channel, it checks whether the other party is present. If not, it sits waiting, during which it consumes no CPU and only a little memory. When the second goroutine arrives at the rendezvous point, data is exchanged then they go their separate ways.

Aside: this concept of rendezvous is quite similar in Ada (also based on Hoare's work), but Ada does not have channels to separate tasks so they must meet explicitly.

For an unbuffered channel, the rendezvous always causes one of the goroutines to wait for the other. When channels have buffering, there are three cases. If the buffer is empty, then the reading goroutine still has to wait for data from a sending goroutine. If the buffer is full, then the sending goroutine has to wait for space before it can complete the rendezvous. In the other case, the buffer is part-full so the reader can always read immediately without waiting, and the writer can always write without waiting.

In Go, buffered channels are always finite in size. Although it is easy to code up a goroutine that acts as a limitless buffered pipe, the normal view is that using limitless buffering is a sign of smelly code, because in reality, memory is always finite.

Unbuffered channels always cause waiting; buffered channels may also cause waiting. The result is that there is flow control across the network of processes - I'll discuss this further later.

Go has a select statement for choosing between alternatives (the CSP choice) which may include channels, timers or simply skipping on to the next thing. This allows what one might call "waiting faster" by picking up from whichever channel is available first. But remember that whilst a goroutine is waiting on the channels (CSP calls them guards) in a select, it consumes no CPU and very little memory.

It is easy to describe Akka actors in terms of goroutines. Each actor is one goroutine that has a 'while true' loop (for { } in Go) enclosing its logic. It has exactly one input channel, which it reads from at the start of every loop. This channel has infinite buffering (let's ignore for now that Go doesn't normally allow this). It also has an unbounded number of writers to the channel; the writer are also actors. In this Go model of Akka, select would never be used.

Note in passing that Go channel ends can be shared: there can be many writers at one end and many readers at the other end; Go sequentially interleaves messages in an arbitrary way.

It's clear from this model that goroutines and channels can be used to describe other network patterns. Essentially, Akka implements a fixed kind  network (of variable topology) in CSP terms. In terms of performance, it does it probably much more efficiently than the equivalent Go would do. One feature of this kind of network is that there is no explicit flow control because no write rendezvous is ever needed on an infinite buffer. The model is fully asynchronous.

Akka also has a superb feature of easily allowing actors to exist on different computers on their network. Message marshalling and routing is handled automatically.

But there are downsides to the actor model.
  • There are cases where flow control is needed. Although these can be implemented in Akka using handshake dialogues, the code gets messy and it's not efficient any more.
  • There is no ability of an actor to refuse to communicate. When a message arrives, it has to be processed or, perhaps, put into a buffer to be dealt with later. A goroutine with more than one channel attached can choose to be in states where it ignores a subset of its channels. The goroutine can select on all or just some of its channels, depending on its state. An example might be an implementation of a simple fixed-size queue goroutine with one input and one output channel. Initially it is empty, so it ignores its output channel. Ultimately, it could be full, when it would ignore its input channel. Otherwise it would select between both channels to decide what to do. Because it is possible for the goroutine to ignore either channel, its logic is expressed nice and simply.
  • Akka places full reliance on the infinite input buffers never running out of memory - but this is not guaranteed.
There is one important downside to the CSP way of networking concurrent behaviour:
  • Any network of goroutines that has some mutual dependency may deadlock. The developer must be aware of this and code so that deadlock is eliminated; this involves identifying mutual dependencies and altering them in some way (there are several well-known techniques, the easiest of these being to use a pure client-server pattern, which is known to be deadlock-free).
But consider what happens if a deadlocking network of goroutines is converted to Akka. The non-blocking communications means that deadlock won't happen - but how can we be sure that the queues will not overflow? There is a direct equivalence between deadlock and exhaustion of not-so-infinite buffers.

Goroutines only work within a single computer (albeit with any number of cores). There is no built-in networking, although external packages add this capability. This differs from Akka; it is also inferior to other CSP-based communications, such as JCSP for Java, which includes channels that operate transparently over network connections, retaining the normal synchronisation semantics.

One final note concerning goroutines is that their termination is arbitrary. Contrast this with Occam (another CSP language), in which processes are 'owned' by their parent, and the parent waits until all its child processes have terminated. It is possible to make Go behave in a more rigorous CSP way (like Occam) by adding synchronisation code explicitly.
Your feedback is private.
Is this answer still relevant and up to date?
Roland Kuhn
Roland Kuhn, Akka Tech Lead, Typesafe Inc.
Disclaimer: I have not used Go, hence my knowledge on that part is limited.

Go Channels model closely the semantics of Communicating sequential processes (Hoare, 1978) while Akka actors implement the Actor model (Hewitt, 1973). Both describe independent processes which communicate via message passing. The main difference is that a message exchange is synchronous in CSP (i.e. a “touch point” of the execution of two processes where they hand over the message) whereas it is completely decoupled in the Actor model, with message delivery being unconfirmed to the sender and taking an arbitrary amount of time. In consequence Actors enjoy much larger independence from each other, since they can choose when to handle which incoming message based on their own state. In Go the programmer must foresee the right sequence of checking for different incoming messages in order not to block the program from making progress. The benefit is that Channels do not need to buffer messages, while Actors require a mailbox of theoretically unbounded size.

Another consequence of decoupling the sending of a message from its processing at the receiver is that it becomes trivial to run both on different network nodes without user-visible change in semantics. It also allows the receiver to be unavailable (e.g. due to a software or hardware failure) without affecting the sender beyond not getting a reply.

In summary Channels are useful for orchestrating concurrent execution in a tightly controlled environment whereas Actors provide an abstraction for loosely coupled, distributed components.
Your feedback is private.
Is this answer still relevant and up to date?
Russell Cohen
Russell Cohen, Wrote a Compiler in Scala
An Akka actor is vehicle for receiving and passing messages to other actors as well as performing computation based on the data it's received.

Goroutines taken away from Go would really just be threads. But Go has channels -- where in Go you'd signal to a goroutine by sending a message on a channel in Akka, you'd send a message to the appropriate actor.

Both systems do fundamentally the same thing but message passing is a first class citizen in actors wheras in Go it's possible by way of channels but message passing isn't required to obtain useful results from a Goroutine.
Your feedback is private.
Is this answer still relevant and up to date?

can we say that in Actor Model, the addressable entity is the Actor, the recipient of message. whereas in Go channels, the addressable entity is the channel, the pipe in which message flows.

in Go channel, you send message to the channel, and any number of recipients can be listening, and one of them will receive the message.

in Actor only one actor to whose actor-ref you send the message, will receive the message.