The simplest way to run computations in parallel is to use parallelApply. This works like apply(BasicList,Function), except that it uses all your cores, and always returns a List.
|
There is some overhead to parallelism, so this will only speed things up for a big computation. If the list is long, it will be split into chunks for each core, reducing the overhead. But the speedup is still limited by the different threads competing for memory, including cpu caches; it is like running Macaulay2 on a computer that is running other big programs at the same time. We can see this using elapsedTime.
|
|
|
You will have to try it on your examples to see how much they speed up.
Warning: Threads computing in parallel can give wrong answers if their code is not "thread safe", meaning they make modifications to memory without ensuring the modifications get safely communicated to other threads. (Thread safety can slow computations some.) Currently, modifications to Macaulay2 variables and mutable hash tables are thread safe, but not changes inside mutable lists. Also, access to external libraries such as singular, etc., may not currently be thread safe.
The rest of this document describes how to control parallel tasks more directly.
The task system schedules functions and inputs to run on a preset number of threads. The number of threads to be used is given by the variable allowableThreads, and may be examined and changed as follows. (allowableThreads is temporarily increased if necessary inside parallelApply.)
|
|
To run a function in another thread use schedule, as in the following example.
|
|
|
|
|
Note that schedule returns a task, not the result of the computation, which will be accessible only after the task has completed the computation.
|
Use isReady to check whether the result is available yet.
|
To wait for the result and then retrieve it, use taskResult.
|
|
It is possible to make a task without starting it running, using createTask.
|
|
Start it running with schedule.
|
|
|
One may use addStartTask to specify that one task is to be started after another one finishes. In the following example, G will start after F finishes.
|
|
|
|
|
|
Use addCancelTask to specify that the completion of one task triggers the cancellation of another, by means of an interrupt exception.
Use addDependencyTask to schedule a task, but to ensure that it will not run until one or more other tasks finish running.
Using the functions above, essentially any parallel functionality needed can be created.
Low level C API functionality using the same scheduler also exists in the Macaulay2/system directory. It works essentially the same way as the Macaulay2 interface.