On Thu, Dec 1, 2016 at 10:38 AM Daniel Fanjul <
daniel.fanjul.alcu...@gmail.com> wrote:

>
> > Inside a single goroutine the code proceeds in statement order.
> The code generated by the compiler, right? Of course, it is typically the
> processor who reorders. But what is the limit of the reorder?
>

The memory model describes a "virtual" CPU which happens to execute
operations in-order for each go-routine. Further it sets up a (causal)
happens-before relationship when synchronizing several goroutines and their
in-order execution. In short, the memory model is a pure logical
construction, not bound to real hardware.

In Computer Science, people tend to belong to either the "theory" side of
things, where you describe algorithms and phenomenon purely detached from
the underlying hardware. Or you belong to the "practical" side of things,
where the hardware is central and you build up the logic from what is
possible with the hardware.

The memory model is where these two worlds meet.

The task for a compiler/runtime writer is to take the virtual model, and
map it onto real hardware. We are allowed a certain amount of leverage
here, as long as we make sure we obey the memory model in the end.
Specifically:

* We can allow the CPU to reorder memory writes, as long as we make sure
there is a memory-barrier instruction inserted in the right place by the
compiler or runtime

* We can allow the compiler to reorder instructions as well, as long as we
have a proof that the reordering preserves the semantics of the program.
Again, we would have to insert a memory barrier in places.

But note if we compile Go to hardware which has in-order execution, one
core, and where there is no cache and no coherency problems, we don't have
to insert a memory-barrier. Hence, the memory model is best written to not
contain a word such as "memory barrier". They are artifacts of the
"practical" hardware, not of the "theoretic" memory-model.

The happens-before relation defines a causal relation between different
goroutines. This is powerful since this is where the leverage is hidden: we
can have a goroutine run as a "soup" of reorderings in limbo until
communication happens. At the point of rendezvous the happens-before
relationship "locks down" the soup and makes sure it is in the right order.
This is often ensured via a memory barrier instruction (or one which that
side-effect). Since we can reorder freely until lock-down occur, we can
optimize code by simultaneous execution of independent statements
(out-of-order execution via Tomasulo's algorithm).

The key is that this actually models the real world. You may get a summary
of a meeting with the findings, but you don't care too much about what was
discussed in the meeting in order to reach those findings. In short, the
discussions are allowed "reordering" leverage, as long as the findings are
locked down in the summary when you hear about them. I.e., there is a
memory barrier happening at the end of the meeting.

Another real world example, of a causal violation this time, is when you
have an image service such as Instagram, Google Images, Snapchat, ...,
where a person first blocks a recipient and then posts an image to
everyone. Because the block happens-before the post, you don't want that
image to end up in the inbox of the blocked person. But if you violate the
causal dependency, then that is exactly what might happen: the image gets
posted first, then the block is instated. Many distributed systems violate
these orderings unless you are careful.

So what is the limit of the memory reorder? The limit is that the causal
(happen-before) consistency must not be violated. You are allowed, as in
the meeting example, to have a *local* violation, as long as external
observers are not able to see that local violation. This allows you to
optimize programs for efficiency, which is a good thing[0]. But that is all
you are allowed.

[0] There is an interesting observation here: local violations
as-long-as-observers-cannot-see-it is the central aspect of APIs and
interfaces. Which has similarity to assuming the truth of a theorem or
lemma in mathematics. Give a module a (purely) functional interface, but in
the actual implementation, use every imperative programming speed trick you
know of, violating FP in the process. The program is still "functional",
though it allows you to violate that property locally.

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to