Thinking in parallel, easy it's like a gatling gun, thinking in async, is like shooting a double-barrel shotgun and keeping track of the buckshot. Any advice on how to plan/reason async, vampire?
Async / Await is designed to solve a specific problem that occurs when writing e.g. a GUI application. Basically Async / Await allows you to minimally change your straightforward blocking implementation to run achieve non-blocking code. FYI Under the covers this is achieved by wrapping the code in a state machine that functions quite similar to the state machines that accompany a typical game run loop.
As for planning / determining a code base propensity for parallelisation; I'll leave the opinions to the others, and rather point to towards a strictly mathematical approach ito concurrency; which originates from two primary branches of mathematics: category theory and abstract algebra:
Designing / Determining Propensity for Parallelisation
The above diagram basically shows that:
are all structures which are considered to be
Magmas i.e. a structure that is equipped with binary operation.
More so a Monoid is both a Semigroup and Magma i.e. it is both associative and includes an identity, where a Bounded Semilattice includes the abilities of the all the other structures: binary operation, associative, identity, commutative and idempotence.
The downward arrow reflects the increase propensity for parallelisation; i.e. a bounded semilattice is highly parellisable where's a semigroup has certain restrictions.
This is naturally a large field of study and relatively complex to learn; however don't get frightened away by the Latin / Greek terms and the mathematical formulations; as it certainly become quite a bit easier to read this over time.
Here's a very quick intro:
Associativity stipulates that groupings are irrelevant, for example:
- 1 + 2 + 3 == (1 + 2) + 3 == 1 + (2 + 3)
This works for both addition and multiplication, but does not work for subtraction or division.
Identity relates to the base value that we start associative operations, for example:
- In addition; zero is the identity because 0 + 1 == 1 (i.e. zero has no effect on the outcome)
- In multiplication, one is the identity, because 1 * 2 == 2 (i.e. one has no effect on the outcome)
Commutativity indicates that order is also irrelevant, for example:
- 1 + 2 + 3 == 2 + 1 + 3 == 3 + 2 + 1
i.e. order of the binary operation doesn't matter. This means that we don't have to concerned about the order in which we combine structures because the result will be the same i.e. we can run on multiple threads and not be concerned about the assembly order.
Idempotence is achieved when a binary operation can be applied multiple times without affecting the result, for example:
- Determining the Math.max or Math.min of a series of integers will always deliver the same result irrespective of how many times the same operation is repeated.
These structures have a high propensity for parellisation, however as the diagram also indicates this is more rare than structures that are only associative.
Ok, so after all of this, you may be wondering if this means that concurrency is only limited to numbers. Good news it isn't, as this is where the abstractness of category theory kicks in, by allowing us to wrap almost any structure in a "wrapper / box type" that support these attributes whilst preserving the values that they wrap. Example of this are: applicative functors, monads, arrows, ...