Nim supports both threads and async/await for concurrency. New libraries are also expanding the choices developers have for concurrency and parallelism.
Parallel and Spawn
According to the Nim v1.2 manual, the new preferred way to achieve parallelism in Nim is to use parallel and/or spawn, found in the threadpool module. Spawn passes a specified task (a procedure) to the threadpool. Parallel creates a section to execute a block in parallel.
- Parallel and Spawn in the Nim manual
- A brief example using spawn and parallel
- Nim’s threadpool module
Nim in Action
- Chapter 3: has a chat application that uses async.
- Chapter 6: concurreny and parallelism (threads).
Example code: https://github.com/dom96/nim-in-action-code
In Nim threads are used as in most languages. The typical approach is that you create a number of threads using createThread() and wait for all of them to finish using joinThreads().
Threads are useful for when you can easily divide work up across a known number. However, knowing the number of threads to use can be difficult. The number of cores in the system can be used as an indicator, but the assumption is that these cores are free for your program to use.
Using threads can be difficult if memory is shared between threads, and that memory is modified by multiple threads. This can introduce bugs that are difficult to detect and fix. You can use locks to handle this. A lock is often called a mutex is other languages.
Async/await is useful for when you want the main thread to keep running, but start work asynchronously, and later wait for the result. This pattern is especially useful in networking and database calls, where you are typically waiting for IO, but your program can keep working while waiting for the result of the IO.
- asyncnet for asynchronous sockets
- asyncdispatch for asynchronous sockets
- Async PostgreSQL connection pool and Nimble directory: pg
- Basic example using async
- Fosdem 2020 Talk: how async await is implemented in Nim
Weave is a multi-threading runtime: https://github.com/mratsim/weave.
- Message-passing based.
- Scalable to available cores.
- Fast and low-overhead.
- Based on futures similar to async/await for concurrency.
Note the current limitations: “Weave has not been tested with GC-ed types. Pass a pointer around or use Nim channels which are GC-aware. If it works, a heads-up would be valuable. This might improve with Nim ARC/new runtime.”
Nim doesn’t have an actors framework/library that is maintained at present.
Parallelism in the Database
Most databases allow for parallelism, especially when working with set operators like UNION or when querying partitions. Details of database parallelism are out of scope for this article, but worth keeping in mind when performance tuning a system that uses a database.