I think a better language to understand the Actor Model with is Elixir. The Actor Model's main point is concurrency. It is hard to demonstrate that in a language that doesn't support concurrency.
Ah. I have a misunderstanding of definition then, since when I think of concurrency I think of interleaved execution irrespective of whether or not this execution is done in parallel.
I tend to adhere to the dictionary definition of the word, which is two things happening or existing simultaneously. However, I do know that proponents of single-core-bound languages like JavaScript, and others, like to talk about concurrency in a single-threaded way.
The computer science definition of concurrency and parellelism are different that what you're explaining. In CS, a program can only be concurrent. Parallel is to do with how it's run, and the hardware. A concurrent program, is still concurrent even if it's run on a single core, whereas to be considered parallel, it must be running on multiple cores/processors/machines/etc. at the same time.
One way to think of it:
If I have three plates of food, that I can eat in any order, but it's just me eating, then this is concurrent. In practice, this is no faster than if I had to eat 1, then 2, then 3, however it has the potential to be. By adding another person, it becomes parallel.
When I was in computer science classes in college, "concurrency" was defined as multiple processes running at the same time on multiple processors. You could not have concurrency with a single core. If all you had was a single core, then the best you could hope for was "pseudo-concurrency," because it is impossible to run two things simultaneously on one core. When did this definition change?
Your food metaphor doesn't really work in the computer science sense, because you cannot concurrently eat three things at the same time unless you put them all on the fork at the same time, which is something you simply cannot do in computer science.
It never did. A concurrent program has always meant a decomposition of a program into parts that can be executed out-of-order while maintaining the same output. Whether or not this is by some scheduler on a single-core cpu is irrelevant to the theory.
The words "concurrency", "multi-threaded", and "parallel" each have different meanings. You can have a program that is multi-threaded but which does not maintain concurrency ie. the output is dependent on race conditions. This is usually, but not always, a bug.
Your confusion stems from the fact that most people do not care about the distinction. You usually don't care about concurrency unless you plan to actually run things in a manner which is unordered. Thus when the theory says "concurrency" you think "parallel". Technically speaking you're wrong, practically speaking your mistake usually won't matter.
As a final example consider a single-core computer running Windows with multiple processes running a myriad of services and programs. At any one time only a single process can run on that single available core, but in practice they are running "at the same time", because the system is implementing a model of concurrency allowing it to schedule and execute the different processes out-of-order.
You don't understand the food metaphor. If you have 3 plates of food, but they can be eaten in any order, then 3 people can eat them in 1/3 the time that 1 person could eat them. The food/plate is the code/data, the person/fork is the processor. You're never eating the same exact piece of food at the same time.
To be frank most of my experience with concurrency (rather than parallelism) is from formal theory taught during my masters studies. But I was rusty, so I was unsure if I remembered incorrectly.
Don't forget fault tolerance! In my particular use cases concurrency is not really necessary, but I love the fact that I don't have to be quite as 'defensive' in my programming. Whenever a particular (Erlang) process/'Actor' fails, its supervisor can simply restart it and I can deal with the cause of failure later while the entire system chugs along (mostly) happily.
Right. Elixir and Erlang's fault tolerance is amazing. I think it is important to point out that to use Elixir's let-it-fail mechanisms, you have to use concurrency. You can't have a supervisor and supervised code running in the same process, so you have to use concurrency in order to benefit from this fault tolerant mechanism.
It depends on how you set things up, but one possible approach is that the supervisor, after a few retries, would also shut down, which would trigger the supervisor above that to restart the whole thing with a different port. This wouldn't make sense, probably, but maybe it illustrates how you can go about these things.