Explain: Don't communicate by sharing memory; share memory by communicating

前端 未结 6 1285
生来不讨喜
生来不讨喜 2020-12-13 02:50

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

相关标签:
6条回答
  • 2020-12-13 03:24

    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.

    0 讨论(0)
  • 2020-12-13 03:25

    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:

    • You have not strictly defined that the "send" you are talking about is a synchronization point. If you mean a send on an unbuffered channel, then yes, that will create a shared synchronization point that by specification introduces a strict happenstance order.
    • While, assuming the above is true, you have described a synchronization point, this only addresses one side of the point of the original advice. The original advice includes the concept of "transfer of ownership", and that has less to do with creating synchronization points or happenstance, and more to do with the longer term maintenance of code that relies on potentially shared memory. The concept is that instead of retaining access to some segment of memory in two places, and creating separate shared synchronization points (like mutexes), one can instead pass, possibly the only, reference to the object from one owner to another. Designing software this way prevents the accidental modification outside of synchronization points, which has often been observed in software with granular use of mutexes and extensive use of shared memory.

    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.

    0 讨论(0)
  • 2020-12-13 03:29

    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!

    0 讨论(0)
  • 2020-12-13 03:42

    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.

    0 讨论(0)
  • 2020-12-13 03:43

    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.

    0 讨论(0)
  • 2020-12-13 03:43

    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 -----
    
    1. This means that different threads of execution would be informed of the change of state of other threads by reading memory that would be modified somewhere else. A perfect example of this (although for processes instead of threads) is the POSIX shared memory API: http://man7.org/linux/man-pages/man7/shm_overview.7.html. This technique needs proper synchronization because data races can occur pretty easily.
    2. Here this means that there is indeed a portion of memory, physical or virtual, that can be modified from several threads, and read from those, too. There is no explicit notion of ownership, the memory space is equally accessible from all threads.
    3. This is entirely different. In Go, sharing memory just like above is possible, and data races can occur pretty easily, so what this actually means is, modifying a variable in a goroutine, be it a simple value like an 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.
    4. Communication here simply means that a channel, which is only a queue, allows one goroutine to read from it and so be notified of the ownership of a new portion of memory, while another one sends it and accepts to lose ownership. It is a simple message passing pattern.

    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.

    0 讨论(0)
提交回复
热议问题