I understand what you're getting at, but I don't think that's a great summary of concurrency vs. parallelism. My version would be: currency is about non-determinism and multiple threads of control while parallelism is about doing multiple computations at once for performance reasons (possibly deterministically).
EDIT: sorry I see this has already been posted almost verbatim a few other places in the thread
Very hard to enforce when you're running a heterogenous network trying to handle routing which may have any kind of app answering requests. If there was an easy solution to this, evidently Heroku would have put it in already, but I'd hope they're working on it.
Sounds like some of their customers have outgrown them though; given the amount they are paying per month they could easily host themselves and hire someone to look after their servers - at some point it becomes necessary to control your entire stack if you're looking at performance.
Infrastructure and techniques that support concurrency (e.g. actors) are almost always totally unsuitable to parallelism (e.g. SIMD ala GPUs), and the other way around. Likewise, skills don't transfer very well between the two fields. So when someone talks about this technology being useful to your use case, and they've confused the terms, its very annoying (you should use actors to get more parallelism, WTF????).
There is a lot of legacy code running with MPI for sure, but the big data and almost big data trends are clear, and CUDA has been absolutely disruptive in the scientific computing field (though some people are beginning to use MapReduce here also).
GPUs, Xeon Phi, FPGAs and other accelerators still need somebody managing them. Nobody said it should be MPI, but there are still many hybrid architectures with MPI handling distribution and actual compute done using OpenMP or accelerators.
In my system I use Erlang/OTP to handle distribution and concurrency and OpenCL for data-parallel compute.
Sounds like Jeff Dean.
> Nobody said it should be MPI, but there are still many hybrid architectures with MPI handling distribution and actual compute done using OpenMP or accelerators.
MPI or even RPC works fine as a control mechanism, just not as a critical performance-sensitive abstraction, where we care about the width and speed of the pipe, and MPI is nothing like a pipe!
> In my system I use Erlang/OTP to handle distribution and concurrency and OpenCL for data-parallel compute.
This is quite reasonable. Once one understands the difference between concurrency and parallelism, they can pick appropriate tools to deal with each. As long as they confuse the issues, they'll make bad choices.
Essentially Go just Limbo, but native instead of VM and with more conventional syntax.
Inferno also had built-in distribution and hot code loading: I.e. you could load module from remote location and run a function locally or you could execute function remotely as RPC.
Erlang/OTP never had this level of integration as Inferno, but now we have some efforts to running Erlang on bar metal, I.e. Erlang-on-Xen.
Concurrency deals with dependency, or the lack of, among tasks and their running order. Task A must run after task B, B after C, etc. A, B, and C are not concurrent tasks. D can run at anytime. D can run before, after, or at the same time of A/B/C. The ordering doesn't matter. In this case D is concurrent to A/B/C. The concurrent tasks MIGHT run at the same time but it's not necessary. It's up to the OS/system scheduler. Concurrent tasks can run on a single core cpu serially and they are still concurrent tasks.
Parallelism has to do with efficiently cranking as many tasks as possible to actually run in parallel. E.g. given 10 cpu, how do I fully utilize all the cpu at the same time? Mostly it has to do with data partition to make sure the cpu can get evenly distributed non-depending data.
Concurrency and parallelism can be mixed at the same time. E.g. in the map-reduce pattern, the map part utilizes parallelism to distribute the data to process at all the cpu. The reduce task has dependency on the mpa tasks; running order means concurrency is in play there.
Goroutines are mapped onto (kernel-level) threads in order to make it possible to run more of them at once and thus provide parallel execution. Otherwise, you have a single scheduler of goroutines in a single process. You can still switch context between the goroutines, thus the system is concurrent. But it will not be parallel: One goroutine only at a time.
For a system in which most goroutines wait on IO or the network, it may not be a problem to run many goroutines on a single core only.
I guess you meant "concurrent execution" here ;)
"Otherwise, you have a single scheduler of goroutines in a single process. ... But it will not be parallel: One goroutine only at a time."
So Go doesn't have something equivalent to SMP scheduler in Erlang?
If you alter the program to spawn a separate thread for each, and let them all block, you will have a parallel solution.
Parallelism : actually running at the same (using different cores)
What most people don't realize is that for concurrency to be useful, there must be parallelism. But wait, didn't I just say that in Node you have concurrency without multiple threads? Yes, but the parallelism does not need to be in your CPU! If you do an asynchronous disk read, or an asynchronous network request, the disk and other computers on your network are working in parallel with your program. Concurrency allows us to exploit that parallelism, so that the CPU can do useful work while the disk is busy reading our data.
Now, you can write your program with concurrency, but if there is no parallelism anywhere in the system, that's not useful. So in practice it is the reverse: concurrency implies parallelism (but not necessarily on the CPU), but parallelism does not imply visible concurrency (though it might be hidden under the hood of a parallel construct like parallel map).
No, as far as I understand from this and other talks, Rob Pike argues that concurrency is useful even without parallelism: it's a better way to structure software. A nice example for this is shown in his talk about lexical scanning in Go: http://www.youtube.com/watch?v=HxaD_trXwRE
Though perhaps "useful" is a bit too broad: maybe it should be replaced by:
> What most people don't realize is that for concurrency to improve performance, there must be parallelism.
Concurrency has absolutely nothing to say about parallelism. If you have a computer system which is able to execute tasks in parallel, it can take advantage of information from the concurrency relation to execute two concurrent tasks in parallel.
For the best implementation of this idea I've seen, I recommend taking a look at Intel's Threading Building Blocks template library.
Multiple threads of control may do things in parallel.
Another good explanation: http://ghcmutterings.wordpress.com/2009/10/06/parallelism-co...
Concurrency is not parallelism, yet.. parallelism requires concurrency...?
I read through your linked article and didn't understand, I read through the linked article and... I still don't understand!
>Now I can hear you object, but isn’t concurrency required to implement parallelism? Well, yes, it is, but concurrency is also required to implement sequentiality too!
What am I missing here?
Is parallelism just a well structured concurrency? Or is the sole distinction determinism vs non-determinism? How is non-determinism avoided in a parallel process (which, to my thinking, means a thread)?
From my Java/Python mind, the load balancer dispatcher/worker/channel-listener seemed very similar in construction to what you would do with a Thread (or Process) and a synchronized Queue. What makes one concurrent, and the other not?
I suppose, my main question is, what prevents parallelism from not being non-deterministic?
The distinction is much easier to understand in haskell because the language is expressive enough, but that blog post might have been too much information. Here's the standard haskell concurrency library:
It provides computations that can be forked on new threads, and primitives for communicating. The threads are scheduled by the runtime (non-deterministic semantics!) and I am free to write and run such a program on the single-core laptop in front of me (no parallelism!).
In contrast take a look at Control.Parallel:
Here all the `par` function does is tell the runtime "it might be helpful to compute these in parallel" (parallelism!), but semantically `par x y` is simply `y` (the type or definition of `par` might not make sense to you, but that's not really important); there have been no new threads of control spawned (deterministic!).
Now if I wanted to, I could write a library for a parallel function `map :: (a -> b) -> Array a -> Array b` say (parallelism!), and I might implement that in terms of the concurrency primitives from Control.Concurrent. I would consider that `map` to be an example of deterministic Parallelism, even though the implementation might be utilizing multiple non-deterministic threads of control (in the same way the `par` is parallelism despite being implemented on top of the runtime, OS/green threads, and all other sorts of magic.
During a one second window, did both of the tasks execute? If yes, then they are concurrent. If no, then they are not concurrent.
Was there any moment in time when both tasks executing simultaneously? If yes, then they executed in parallel. If no, then they did not execute in parallel.
From this, it's easy to see that if something is parallel, it must also be concurrent - in order for two tasks to execute during the same moment in time, they must also both have executed during a window of time.
Concurrency without parallelism happens on machines with a single core. Processes and threads must time-share the only core. Frequently, some of these processes will have multiple threads, so the threads need to synchronize with each other, even though they don't execute at the same time.
The definitions of concurrency and parallelism have nothing to do with determinism, so I don't know why others have brought it up. Concurrency and parallelism implies non-deterministic interleavings of threads and processes, but whether or not the result is deterministic is up to how we program.