← Back to context

Comment by skew-aberration

3 hours ago

It's interesting that we've gone from cooperative to preemptive to cooperative multitasking again.

I agree that blocking threads is generally more natural / obvious. Cooperative multitasking was always done for performance reasons and more recently for simplicity (in single thread implementations with no locking) and/or scaling reasons.

Message passing concurrency is going even further though, and never really seems to have taken off wholistically. Again, primarily for performance reasons. When we do pass messages (across networks, too/from RAM or disk, etc) we usually add caching and other optimizations which make concurrency even harder to reason about.

Message-passing is popular in HPC (e.g. MPI) because it more closely models how hardware works. But at a higher level people mostly prefer to build abstractions on top of it like async/await because message-passing requires you to manually compile your flows into per-process state machines, and that's not how most people think about flows (even though business people do sometimes: https://link.springer.com/chapter/10.1007/978-3-540-72863-4_...).

Message passing on virtual threads on the JVM allows you to run millions of threads and it has no performance downside to async.

  • Every copy is a performance downside. There's plenty of applications where it is essential to use shared memory. You could not rewrite Linux to avoid shared memory between threads.

    The line is fuzzy though.

    You might say that each RAM access is really a message over a bus, and so is each cache access. Conversely, you could write a message passing style key value store and create race conditions by using like shared memory.

    Transactional memory is also 'message passing' like -> you bundle up access of shared memory into a single transaction 'message'.

    A lot of shared memory code uses constructions like FIFO/queues which are really not too distinct from message passing except when ownership is shared or goes back and forth. Perhaps that's just an 'implementation' of message passing.

    • Message-passing doesn't necessarily involve naïvely copying the data around. If you have access to shared memory then you can pass a pointer; the only thing you really need to ‘pass’ is the capability to access the message data. This is how seL4 does it, for example.

      Of course if you don't have shared memory then you have to copy anyway :) And because of CPU caching architecture the benefits of having an owned copy of the data can sometimes outweigh the cost of copying it, even if shared memory is available.

> wholistically

You made me curious about the spelling of 'holistic', given that it really is based on the concept of wholeness. It turns out:

- Holistic is formed from the Greek root hol-, meaning "whole". Like hologram.

- It's even closer to the English than it looks; modern whole descends from Old English hal (cognate to the Greek word), which also gives us hale and health. The W in the modern spelling is a spurious addition unrelated to the etymology of the word. You'd expect "hole".

- Who is different, and the W in that word is etymologically correct. (Old English hwa.)