Parallelism

Parallelism in Chapel is provided by the language itself in contrast to Python, which relies on modules and libraries. This section contains fewer side-by-side examples, as most of these features are harder to come by in Python. Instead, reference to libraries will be provided.

Task Parallelism

In Chapel, orchestration of parallel execution is provided by the built-in keywords: begin, sync, cobegin, and atomic variables (atomic). Task parallelism in Python is provided through libraries such as: multiprocessing, threading, thread, Queue, queue, Mutex, and mutex.

If you are used to the multiprocessing and threading libraries, then think of a Chapel task as either a multiprocessing.Process or a threading.Thread.

begin and sync

The examples below implement equivalent programs in Python and Chapel: a function is executed in parallel, arguments are passed to the function and the main program waits for the function to finish.

Python   Chapel
from multiprocessing import Process

def f(name):
    print('Hello, '+ name)

if __name__ == '__main__':
    p = Process(target=f, args=('bob',))
    p.start()
    p.join()
 
proc f(name) {
    writeln("Hello, ", name);
}

proc main() {
    sync begin f("bob");
}

In Chapel, the spawning of a task is done by using the begin statement, while Python requires the instantiation of a Process targeting a function and invoking the start method. Waiting for the parallel execution to finish is done by applying the sync statement in Chapel and invoking the join method in Python.

Spawning a task in Chapel does not require specifying a target function, blocks of code can be used:

Chapel
var name = "Bob";
writeln("Let us make ", name, " feel welcome.");
begin {
    writeln("Hi ", name);
    writeln("Pleased to meet you.");
}
writeln("Done welcoming ", name);

Which also illustrates how you can share data between tasks. Data within scope is available to the task and it is therefore not nescesarry to pass it argument via a function-call.

If you try to execute the example above you might notice that the spawning task prints out “Done welcoming …” prematurely (prior to the spawned task printing “Welcome, …”.

This is just to emphasize the use of the sync statement which blocks until the parallel execution finishes. So to ensure the correct ordering, apply the sync statement as done below:

Chapel
var name = "Bob";
writeln("Let us make ", name, " feel welcome.");
sync begin {
    writeln("Hi ", name);
    writeln("Pleased to meet you.");
}
writeln("Done welcoming ", name);

cobegin

begin spawns off given statement as a single task, the cobegin statement spawns off multiple tasks; one for each statement in the given block of statements.

Chapel
var name = "Bob";
writeln("Let us all say hi. ");
cobegin {
    writeln("Hi ", name, "i am Alice");
    writeln("Hi ", name, "i am John.");
    writeln("Hi ", name, "i am Jane.");
    writeln("Hi ", name, "i am Richard.");
    writeln("Hi ", name, "i am Norma.");
}
writeln("Done welcoming ", name);

In addition to spawning a task for each statement within the block, the cobegin also implicitly syncs. That is, it waits for all the statements within the block to finish executing. The above could also be expressed in terms of begin and sync by:

Chapel
var name = "Bob";
writeln("Let us all say hi. ");
sync {
    begin writeln("Hi ", name, "i am Alice");
    begin writeln("Hi ", name, "i am John.");
    begin writeln("Hi ", name, "i am Jane.");
    begin writeln("Hi ", name, "i am Richard.");
    begin writeln("Hi ", name, "i am Norma.");
}
writeln("Done welcoming ", name);

Synchronization Variables

sync, single, and atomic

Data Parallelism

forall, domains, arrays, reduce, scan …

Locality

locale, on

Domain Maps