Nim has two flavors of parallelism:
Structured parallelism via the parallel statement.
Unstructured parallelism via the standalone spawn statement.
Nim has a builtin thread pool that can be used for CPU intensive tasks. For IO intensive tasks the async and await features should be used instead. Both parallel and spawn need the threadpool module to work.
Somewhat confusingly, spawn is also used in the parallel statement with slightly different semantics. spawn always takes a call expression of the form f(a, ...). Let T be f's return type. If T is void then spawn's return type is also void otherwise it is FlowVar[T].
Within a parallel section sometimes the FlowVar[T] is eliminated to T. This happens when T does not contain any GC'ed memory. The compiler can ensure the location in location = spawn f(...) is not read prematurely within a parallel section and so there is no need for the overhead of an indirection via FlowVar[T] to ensure correctness.
Note: Currently exceptions are not propagated between spawn'ed tasks!