I wonder what is the most down to earth explanation of this famous quote:
Don\'t communicate by sharing memory; share memory by communicating. (R. Pik
Let me go simple and to the point here.
Don't communicate by sharing memory.
It is like when your are communicating using threads for example you have to use variables or mutexes to lock memory for not allowing someone to read and write on it until the communication is complete.
Share memory by communicating
In go routines values move on channels rather than blocking the memory, sender notifies receiver to receive from that channel and hence it share memory by communicating with receiver to get from a channel.
1) Is my conclusion correct?
I think so, if it means what I hope it does. The reason for the language in the specs using the "happenstance" terminology is that it provides a well defined form of communication for expressing ideas.
The problem with your description is that you haven't actually explicitly defined your happenstance order. I think though that you are implying an order. If you mean that "operations in goroutine a that happen before goroutine a operates on a particular point of synchronization will be visible by goroutine b after goroutine b has also observed that same point of synchronization" - even here though, the "point of synchronization" is poorly defined - though I expect you understand it. Such a point can be defined in happenstance, as the specification does.
2) Does my explanation help?
Maybe, people unfamiliar with the topic or that are struggling with understanding the happenstance style of description may find your description easier to interpret. There are however limitations and potential practical problems in the application your description, as follows:
Mutexes or "explicit synchronization points" are exactly the opposite of the advice - they are a shared piece of memory that is used to communicate a synchronization point "communicate by sharing memory", whereas, even though they have mutexes deep under the hood, channels are an abstract mechanism to pass ownership of an object (the sent value) from one goroutine (sender) to another goroutine (receiver). The point there is, ignoring how channels are implemented, that the user has shared memory (the value) by communicating it from one owner (goroutine a) to another (goroutine b). If you are using a channel to send unrelated data to create a synchronization point, you're essentially using it as a mutex, and this is closer to communicate by sharing memory (focus on the channel), rather than sharing by communicating (focus on the value).
I hope this helps.
There are two sentences in this; for fuller understanding these must be looked separately first, and then clubbed together, So:
Don't communicate by sharing memory;
means, different threads should not communicate with each other by complying to the stringent and error-prone memory visibility and synchronization policies like memory barrier etc. (Note that it can be done, but it can soon become complex and very buggy with data races). So avoid complying to manual, programmatic visibility constructs mostly attained thru proper synchronizations in programming languages like Java.
share memory by communicating.
means if one thread has made any changes (writes) to a memory area, it should communicate the same (the memory area) to the thread interested in that same memory area; note this has already restricted the scope of memory to only two threads.
Now read the above two paragraphs in conjunction with the golang memory model which says, A send on a channel happens before the corresponding receive from that channel completes.
The happens-before relationship confirms that the write by first goroutine will-be visible to the second goroutine receiving the memory reference at the other end of the channel!
I don't think so. The gist is instead of protecting one fixed memory address with a lock or other concurrent primitives, you can architect the program in a way that only one stream of execution is allowed to access this memory by design.
The easy way to achieve this is to share the reference to the memory by channels. Once you send the reference over the channel you forget it. In this way only the routine that will consume that channel will have access to it.
In essence, yes. Any values that are assigned to variables before the channel send are eligible to be observed after the channel read, since the channel operation imposes an ordering constraint. But it's important to remember the other part of the equation: if you want to guarantee that those values are observed, you have to make sure that no one else can write to those variables in between the write and the read. Obviously using locks would be possible, but pointless at the same time because if you're already combining locks and cross-thread memory modification, what benefit are you getting from channels? You could pass around something as simple as a boolean, as a token allowing exclusive access to the global data, and it would be 100% correct in terms of the memory model guarantees (as long as your code didn't have bugs), it would just probably be a bad design because you would be making things all implicit and action-at-a-distance-y without a good reason; passing the data explicitly is usually going to be clearer and less error-prone.
This famous quote can be a little bit confusing if taken too litterally. Let's break it down to its more basic components, and define them properly:
Don't communicate by sharing memory; share memory by communicating
---- 1 ---- ------ 2 ----- ---- 3 ----- ----- 4 -----
int
or a complicated data structure like a map, and give away ownership by sending the value or a pointer to the value to a different goroutine via the channel mechanism. So ideally, there is no shared space, each goroutine only sees the portion of memory it owns.In conclusion, what the quote means can be summed up like this:
Don't overengineer inter-thread communication by using shared memory and complicated, error-prone synchronisation primitives, but instead use message-passing between goroutines (green threads) so variables and data can be used in sequence between those.
The use of the word sequence here is noteworthy, because it describes the philosophy that inspired the concept of goroutines and channels: Communicating Sequential Processes.