Global variables. Global variables make your routines lack the
noSideEffect effect that is required for using either createThread or spawn
safely.
Don’t use createThread unless you implement your own thread pool.
Don’t use ref. Prefer seq as seq lacks the problematic aliasing aspects and
can be moved around just as easily as a ref.
Avoid channels as these do not compose well with potential concurrency,
where the runtime system is free not to exploit the concurrency and to
run a task on the same thread instead.
46.2. What to use
Malebolgia’s abstractions have been the result of years of research and cover
most use cases:
Use parMap, parFind, and parReduce which work at a very high level and
are easy to use correctly and hard to use incorrectly.
Use spawn and awaitAll or alternatives that enforce structured
concurrency.
Share memory via a Locker[T] wrapper that ensures at compile time that
data races cannot happen.
In some sense Malebolgia’s abstractions are the most natural extensions that
add concurrency to “single-threaded” Nim:
• Function call expressions can be run in parallel via spawn. Divergent
281
control flow, as it exists in the single-threaded Nim in the form of case or
if statements, eventually converges again via awaitAll.
• Spawned function calls can return values.
• Global variables or shared memory in the form of var parameters are
enabled with Locker[T].