[Chapel/en] Update chapel.html.markdown (#3877)

This commit is contained in:
Yujia Qiao 2024-05-14 03:28:48 +08:00 committed by GitHub
parent 781ebf270b
commit 950adf2cc3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -13,42 +13,60 @@ as well as multi-kilocore supercomputers.
More information and support can be found at the bottom of this document.
You can refer to the official site for [latest version](https://chapel-lang.org/docs/master/primers/learnChapelInYMinutes.html) of this document.
```chapel
/*
Learn Chapel in Y Minutes
This primer will go over basic syntax and concepts in Chapel.
Last sync with official page: Sun, 08 Mar 2020 08:05:53 +0000
*/
// Comments are C-family style
// one line comment
/*
multi-line comment
multi-line comment
*/
// Basic printing
/*
Basic printing
*/
write("Hello, ");
writeln("World!");
// write and writeln can take a list of things to print.
// ``write`` and ``writeln`` can take a list of things to print.
// Each thing is printed right next to the others, so include your spacing!
writeln("There are ", 3, " commas (\",\") in this line of code");
// Different output channels:
use IO; // Required for accessing the alternative output channels
stdout.writeln("This goes to standard output, just like plain writeln() does");
stderr.writeln("This goes to standard error");
/*
Variables
*/
// Variables don't have to be explicitly typed as long as
// the compiler can figure out the type that it will hold.
// 10 is an int, so myVar is implicitly an int
// 10 is an ``int``, so ``myVar`` is implicitly an ``int``
var myVar = 10;
myVar = -10;
var mySecondVar = myVar;
// var anError; would be a compile-time error.
// ``var anError;`` would be a compile-time error.
// We can (and should) explicitly type things.
var myThirdVar: real;
var myFourthVar: real = -1.234;
myThirdVar = myFourthVar;
// Types
/*
Types
*/
// There are a number of basic types.
var myInt: int = -1000; // Signed ints
@ -75,39 +93,45 @@ type RGBColor = 3*chroma; // Type representing a full color
var black: RGBColor = (0,0,0);
var white: RGBColor = (255, 255, 255);
// Constants and Parameters
/*
Constants and Parameters
*/
// A const is a constant, and cannot be changed after set in runtime.
// A ``const`` is a constant, and cannot be changed after set in runtime.
const almostPi: real = 22.0/7.0;
// A param is a constant whose value must be known statically at
// A ``param`` is a constant whose value must be known statically at
// compile-time.
param compileTimeConst: int = 16;
// The config modifier allows values to be set at the command line.
// Set with --varCmdLineArg=Value or --varCmdLineArg Value at runtime.
// The ``config`` modifier allows values to be set at the command line.
// Set with ``--varCmdLineArg=Value`` or ``--varCmdLineArg Value`` at runtime.
config var varCmdLineArg: int = -123;
config const constCmdLineArg: int = 777;
// config param can be set at compile-time.
// Set with --set paramCmdLineArg=value at compile-time.
// ``config param`` can be set at compile-time.
// Set with ``--set paramCmdLineArg=value`` at compile-time.
config param paramCmdLineArg: bool = false;
writeln(varCmdLineArg, ", ", constCmdLineArg, ", ", paramCmdLineArg);
// References
/*
References
*/
// ref operates much like a reference in C++. In Chapel, a ref cannot
// ``ref`` operates much like a reference in C++. In Chapel, a ``ref`` cannot
// be made to alias a variable other than the variable it is initialized with.
// Here, refToActual refers to actual.
// Here, ``refToActual`` refers to ``actual``.
var actual = 10;
ref refToActual = actual;
ref refToActual = actual;
writeln(actual, " == ", refToActual); // prints the same value
actual = -123; // modify actual (which refToActual refers to)
writeln(actual, " == ", refToActual); // prints the same value
refToActual = 99999999; // modify what refToActual refers to (which is actual)
writeln(actual, " == ", refToActual); // prints the same value
// Operators
/*
Operators
*/
// Math operators:
var a: int, thisInt = 1234, thatInt = 5678;
@ -146,7 +170,7 @@ a <<= 3; // Left-bit-shift-equals (a = a << 10;)
// Unlike other C family languages, there are no
// pre/post-increment/decrement operators, such as:
//
// ++j, --j, j++, j--
// ``++j``, ``--j``, ``j++``, ``j--``
// Swap operator:
var old_this = thisInt;
@ -156,7 +180,9 @@ writeln((old_this == thatInt) && (old_that == thisInt));
// Operator overloads can also be defined, as we'll see with procedures.
// Tuples
/*
Tuples
*/
// Tuples can be of the same type or different types.
var sameTup: 2*int = (10, -1);
@ -179,16 +205,18 @@ writeln(diffTup == (tupInt, tupReal, tupCplx));
// They are also useful for writing a list of variables, as is common in debugging.
writeln((a,b,thisInt,thatInt,thisBool,thatBool));
// Control Flow
/*
Control Flow
*/
// if - then - else works just like any other C-family language.
// ``if`` - ``then`` - ``else`` works just like any other C-family language.
if 10 < 100 then
writeln("All is well");
if -1 < 1 then
writeln("Continuing to believe reality");
else
writeln("Send mathematician, something is wrong");
writeln("Send mathematician, something's wrong");
// You can use parentheses if you prefer.
if (10 > 100) {
@ -209,11 +237,11 @@ if a % 3 == 0 {
writeln(b, " is divided by 3 with a remainder of 2.");
}
// Ternary: if - then - else in a statement.
// Ternary: ``if`` - ``then`` - ``else`` in a statement.
var maximum = if thisInt < thatInt then thatInt else thisInt;
// select statements are much like switch statements in other languages.
// However, select statements do not cascade like in C or Java.
// ``select`` statements are much like switch statements in other languages.
// However, ``select`` statements don't cascade like in C or Java.
var inputOption = "anOption";
select inputOption {
when "anOption" do writeln("Chose 'anOption'");
@ -223,11 +251,11 @@ select inputOption {
}
otherwise {
writeln("Any other Input");
writeln("the otherwise case does not need a do if the body is one line");
writeln("the otherwise case doesn't need a do if the body is one line");
}
}
// while and do-while loops also behave like their C counterparts.
// ``while`` and ``do``-``while`` loops also behave like their C counterparts.
var j: int = 1;
var jSum: int = 0;
while (j <= 1000) {
@ -242,8 +270,8 @@ do {
} while (j <= 10000);
writeln(jSum);
// for loops are much like those in Python in that they iterate over a
// range. Ranges (like the 1..10 expression below) are a first-class object
// ``for`` loops are much like those in python in that they iterate over a
// range. Ranges (like the ``1..10`` expression below) are a first-class object
// in Chapel, and as such can be stored in variables.
for i in 1..10 do write(i, ", ");
writeln();
@ -261,7 +289,9 @@ for x in 1..10 {
writeln();
}
// Ranges and Domains
/*
Ranges and Domains
*/
// For-loops and arrays both use ranges and domains to define an index set that
// can be iterated over. Ranges are single dimensional integer indices, while
@ -277,17 +307,18 @@ var rangeEmpty: range = 100..-100; // this is valid but contains no indices
var range1toInf: range(boundedType=BoundedRangeType.boundedLow) = 1.. ; // 1, 2, 3, 4, 5, ...
var rangeNegInfTo1 = ..1; // ..., -4, -3, -2, -1, 0, 1
// Ranges can be strided (and reversed) using the by operator.
// Ranges can be strided (and reversed) using the ``by`` operator.
var range2to10by2: range(stridable=true) = 2..10 by 2; // 2, 4, 6, 8, 10
var reverse2to10by2 = 2..10 by -2; // 10, 8, 6, 4, 2
var trapRange = 10..1 by -1; // Do not be fooled, this is still an empty range
writeln("Size of range ", trapRange, " = ", trapRange.length);
writeln("Size of range '", trapRange, "' = ", trapRange.size);
// Note: range(boundedType= ...) and range(stridable= ...) are only
// Note: ``range(boundedType= ...)`` and ``range(stridable= ...)`` are only
// necessary if we explicitly type the variable.
// The end point of a range can be determined using the count (#) operator.
// The end point of a range can be computed by specifying the total size
// of the range using the count (``#``) operator.
var rangeCount: range = -5..#12; // range from -5 to 6
// Operators can be mixed.
@ -297,8 +328,8 @@ writeln(rangeCountBy);
// Properties of the range can be queried.
// In this example, printing the first index, last index, number of indices,
// stride, and if 2 is include in the range.
writeln((rangeCountBy.first, rangeCountBy.last, rangeCountBy.length,
rangeCountBy.stride, rangeCountBy.member(2)));
writeln((rangeCountBy.first, rangeCountBy.last, rangeCountBy.size,
rangeCountBy.stride, rangeCountBy.contains(2)));
for i in rangeCountBy {
write(i, if i == rangeCountBy.last then "\n" else ", ");
@ -322,7 +353,7 @@ for idx in twoDimensions do
write(idx, ", ");
writeln();
// These tuples can also be deconstructed.
// These tuples can also be destructured.
for (x,y) in twoDimensions {
write("(", x, ", ", y, ")", ", ");
}
@ -352,7 +383,9 @@ var domainB = {-5..5, 1..10};
var domainC = domainA[domainB];
writeln((domainA, domainB, domainC));
// Arrays
/*
Arrays
*/
// Arrays are similar to those of other languages.
// Their sizes are defined using domains that represent their indices.
@ -364,9 +397,9 @@ for i in 1..10 do
intArray[i] = -i;
writeln(intArray);
// We cannot access intArray[0] because it exists outside
// of the index set, {1..10}, we defined it to have.
// intArray[11] is illegal for the same reason.
// We cannot access ``intArray[0]`` because it exists outside
// of the index set, ``{1..10}``, we defined it to have.
// ``intArray[11]`` is illegal for the same reason.
var realDomain: domain(2) = {1..5,1..7};
var realArray: [realDomain] real;
var realArray2: [1..5,1..7] real; // equivalent
@ -396,9 +429,9 @@ for value in realArray {
writeln(rSum, "\n", realArray);
// Associative arrays (dictionaries) can be created using associative domains.
var dictDomain: domain(string) = { "one", "two" };
var dict: [dictDomain] int = ["one" => 1, "two" => 2];
dict["three"] = 3; // Adds 'three' to 'dictDomain' implicitly
var dictDomain: domain(string) = { "one", "two", "three"};
var dict: [dictDomain] int = ["one" => 1, "two" => 2, "three" => 3];
for key in dictDomain.sorted() do
writeln(dict[key]);
@ -407,9 +440,9 @@ for key in dictDomain.sorted() do
var thisArray : [0..5] int = [0,1,2,3,4,5];
var thatArray : [0..5] int;
// First, simply assign one to the other. This copies thisArray into
// thatArray, instead of just creating a reference. Therefore, modifying
// thisArray does not also modify thatArray.
// First, simply assign one to the other. This copies ``thisArray`` into
// ``thatArray``, instead of just creating a reference. Therefore, modifying
// ``thisArray`` does not also modify ``thatArray``.
thatArray = thisArray;
thatArray[1] = -1;
@ -425,7 +458,7 @@ var thisPlusThat = thisArray + thatArray;
writeln(thisPlusThat);
// Moving on, arrays and loops can also be expressions, where the loop
// body expression is the result of each iteration.
// body's expression is the result of each iteration.
var arrayFromLoop = for i in 1..10 do i;
writeln(arrayFromLoop);
@ -435,16 +468,18 @@ var evensOrFives = for i in 1..10 do if (i % 2 == 0 || i % 5 == 0) then i;
writeln(arrayFromLoop);
// Array expressions can also be written with a bracket notation.
// Note: this syntax uses the forall parallel concept discussed later.
// Note: this syntax uses the ``forall`` parallel concept discussed later.
var evensOrFivesAgain = [i in 1..10] if (i % 2 == 0 || i % 5 == 0) then i;
// They can also be written over the values of the array.
arrayFromLoop = [value in arrayFromLoop] value + 1;
// Procedures
/*
Procedures
*/
// Chapel procedures have similar syntax functions in other languages.
// Chapel procedures have similar syntax functions in other languages.
proc fibonacci(n : int) : int {
if n <= 1 then return n;
return fibonacci(n-1) + fibonacci(n-2);
@ -482,10 +517,10 @@ writeln(defaultsProc(x=11));
writeln(defaultsProc(x=12, y=5.432));
writeln(defaultsProc(y=9.876, x=13));
// The ? operator is called the query operator, and is used to take
// The ``?`` operator is called the query operator, and is used to take
// undetermined values like tuple or array sizes and generic types.
// For example, taking arrays as parameters. The query operator is used to
// determine the domain of A. This is uesful for defining the return type,
// determine the domain of ``A``. This is useful for defining the return type,
// though it's not required.
proc invertArray(A: [?D] int): [D] int{
for a in A do a = -a;
@ -509,7 +544,7 @@ genericProc(1, 2);
genericProc(1.2, 2.3);
genericProc(1.0+2.0i, 3.0+4.0i);
// We can also enforce a form of polymorphism with the where clause
// We can also enforce a form of polymorphism with the ``where`` clause
// This allows the compiler to decide which function to use.
// Note: That means that all information needs to be known at compile-time.
// The param modifier on the arg is used to enforce this constraint.
@ -526,13 +561,13 @@ proc whereProc(param N : int): void
whereProc(10);
whereProc(-1);
// whereProc(0) would result in a compiler error because there
// are no functions that satisfy the where clause's condition.
// We could have defined a whereProc without a where clause
// ``whereProc(0)`` would result in a compiler error because there
// are no functions that satisfy the ``where`` clause's condition.
// We could have defined a ``whereProc`` without a ``where`` clause
// that would then have served as a catch all for all the other cases
// (of which there is only one).
// where clauses can also be used to constrain based on argument type.
// ``where`` clauses can also be used to constrain based on argument type.
proc whereType(x: ?t) where t == int {
writeln("Inside 'int' version of 'whereType': ", x);
}
@ -544,7 +579,9 @@ proc whereType(x: ?t) {
whereType(42);
whereType("hello");
// Intents
/*
Intents
*/
/* Intent modifiers on the arguments convey how those arguments are passed to the procedure.
@ -571,7 +608,7 @@ intentsProc(inVar, outVar, inoutVar, refVar);
writeln("Outside After: ", (inVar, outVar, inoutVar, refVar));
// Similarly, we can define intents on the return type.
// refElement returns a reference to an element of array.
// ``refElement`` returns a reference to an element of array.
// This makes more practical sense for class methods where references to
// elements in a data-structure are returned via a method or iterator.
proc refElement(array : [?D] ?T, idx) ref : T {
@ -586,14 +623,16 @@ refToElem = -2; // modify reference which modifies actual value in array
writeln(refToElem);
writeln(myChangingArray);
// Operator Definitions
/*
Operator Definitions
*/
// Chapel allows for operators to be overloaded.
// We can define the unary operators:
// + - ! ~
// ``+ - ! ~``
// and the binary operators:
// + - * / % ** == <= >= < > << >> & | ˆ by
// += -= *= /= %= **= &= |= ˆ= <<= >>= <=>
// ``+ - * / % ** == <= >= < > << >> & | ˆ by``
// ``+= -= *= /= %= **= &= |= ˆ= <<= >>= <=>``
// Boolean exclusive or operator.
proc ^(left : bool, right : bool): bool {
@ -605,25 +644,28 @@ writeln(false ^ true);
writeln(true ^ false);
writeln(false ^ false);
// Define a * operator on any two types that returns a tuple of those types.
// Define a ``*`` operator on any two types that returns a tuple of those types.
proc *(left : ?ltype, right : ?rtype): (ltype, rtype) {
writeln("\tIn our '*' overload!");
return (left, right);
}
writeln(1 * "a"); // Uses our * operator.
writeln(1 * 2); // Uses the default * operator.
writeln(1 * "a"); // Uses our ``*`` operator.
writeln(1 * 2); // Uses the default ``*`` operator.
// Note: You could break everything if you get careless with your overloads.
// This here will break everything. Don't do it.
/*
proc +(left: int, right: int): int {
return left - right;
}
/*
proc +(left: int, right: int): int {
return left - right;
}
*/
// Iterators
/*
Iterators
*/
// Iterators are sisters to the procedure, and almost everything about
// procedures also applies to iterators. However, instead of returning a single
@ -656,7 +698,7 @@ for i in absolutelyNothing(10) {
}
// We can zipper together two or more iterators (who have the same number
// of iterations) using zip() to create a single zipped iterator, where each
// of iterations) using ``zip()`` to create a single zipped iterator, where each
// iteration of the zipped iterator yields a tuple of one value yielded
// from each iterator.
for (positive, negative) in zip(1..5, -5..-1) do
@ -683,11 +725,10 @@ for (i, j) in zip(toThisArray.domain, -100..#5) {
}
writeln(toThisArray);
// This is very important in understanding why this statement exhibits a
// runtime error.
// This is very important in understanding why this statement exhibits a runtime error.
/*
var iterArray : [1..10] int = [i in 1..10] if (i % 2 == 1) then i;
/*
var iterArray : [1..10] int = [i in 1..10] if (i % 2 == 1) then i;
*/
// Even though the domain of the array and the loop-expression are
@ -695,8 +736,9 @@ writeln(toThisArray);
// Because iterators can yield nothing, that iterator yields a different number
// of things than the domain of the array or loop, which is not allowed.
// Classes
/*
Classes
*/
// Classes are similar to those in C++ and Java, allocated on the heap.
class MyClass {
@ -704,13 +746,16 @@ class MyClass {
var memberInt : int;
var memberBool : bool = true;
// Explicitly defined initializer.
// We also get the compiler-generated initializer, with one argument per field.
// Note that soon there will be no compiler-generated initializer when we
// define any initializer(s) explicitly.
proc init(val : real) {
this.memberInt = ceil(val): int;
}
// By default, any class that doesn't define an initializer gets a
// compiler-generated initializer, with one argument per field and
// the field's initial value as the argument's default value.
// Alternatively, the user can define initializers manually as shown
// in the following commented-out routine:
//
/* // proc init(val : real) {
// this.memberInt = ceil(val): int;
// }
*/
// Explicitly defined deinitializer.
// If we did not write one, we would get the compiler-generated deinitializer,
@ -738,37 +783,45 @@ class MyClass {
} // end MyClass
// Call compiler-generated initializer, using default value for memberBool.
var myObject = new MyClass(10);
myObject = new MyClass(memberInt = 10); // Equivalent
writeln(myObject.getMemberInt());
{
var myObject = new owned MyClass(10);
myObject = new owned MyClass(memberInt = 10); // Equivalent
writeln(myObject.getMemberInt());
// Same, but provide a memberBool value explicitly.
var myDiffObject = new MyClass(-1, true);
myDiffObject = new MyClass(memberInt = -1,
memberBool = true); // Equivalent
writeln(myDiffObject);
// Same, but provide a memberBool value explicitly.
var myDiffObject = new owned MyClass(-1, true);
myDiffObject = new owned MyClass(memberInt = -1,
memberBool = true); // Equivalent
writeln(myDiffObject);
// Call the initializer we wrote.
var myOtherObject = new MyClass(1.95);
myOtherObject = new MyClass(val = 1.95); // Equivalent
writeln(myOtherObject.getMemberInt());
// Similar, but rely on the default value of memberInt, passing in memberBool.
var myThirdObject = new owned MyClass(memberBool = true);
writeln(myThirdObject);
// We can define an operator on our class as well, but
// the definition has to be outside the class definition.
proc +(A : MyClass, B : MyClass) : MyClass {
return new MyClass(memberInt = A.getMemberInt() + B.getMemberInt(),
memberBool = A.getMemberBool() || B.getMemberBool());
// If the user-defined initializer above had been uncommented, we could
// make the following calls:
//
/* // var myOtherObject = new MyClass(1.95);
// myOtherObject = new MyClass(val = 1.95);
// writeln(myOtherObject.getMemberInt());
*/
// We can define an operator on our class as well, but
// the definition has to be outside the class definition.
proc +(A : MyClass, B : MyClass) : owned MyClass {
return
new owned MyClass(memberInt = A.getMemberInt() + B.getMemberInt(),
memberBool = A.getMemberBool() || B.getMemberBool());
}
var plusObject = myObject + myDiffObject;
writeln(plusObject);
// Destruction of an object: calls the deinit() routine and frees its memory.
// ``unmanaged`` variables should have ``delete`` called on them.
// ``owned`` variables are destroyed when they go out of scope.
}
var plusObject = myObject + myDiffObject;
writeln(plusObject);
// Destruction.
delete myObject;
delete myDiffObject;
delete myOtherObject;
delete plusObject;
// Classes can inherit from one or more parent classes
class MyChildClass : MyClass {
var memberComplex: complex;
@ -780,42 +833,46 @@ class GenericClass {
var classDomain: domain(1);
var classArray: [classDomain] classType;
// Explicit constructor.
proc GenericClass(type classType, elements : int) {
this.classDomain = {1..#elements};
// Explicit initializer.
proc init(type classType, elements : int) {
this.classType = classType;
this.classDomain = {1..elements};
// all generic and const fields must be initialized in "phase 1" prior
// to a call to the superclass initializer.
}
// Copy constructor.
// Note: We still have to put the type as an argument, but we can
// default to the type of the other object using the query (?) operator.
// Further, we can take advantage of this to allow our copy constructor
// to copy classes of different types and cast on the fly.
proc GenericClass(other : GenericClass(?otherType),
type classType = otherType) {
// Copy-style initializer.
// Note: We include a type argument whose default is the type of the first
// argument. This lets our initializer copy classes of different
// types and cast on the fly.
proc init(other : GenericClass(?),
type classType = other.classType) {
this.classType = classType;
this.classDomain = other.classDomain;
// Copy and cast
for idx in this.classDomain do this[idx] = other[idx] : classType;
this.classArray = for o in other do o: classType; // copy and cast
}
// Define bracket notation on a GenericClass
// object so it can behave like a normal array
// i.e. objVar[i] or objVar(i)
// i.e. ``objVar[i]`` or ``objVar(i)``
proc this(i : int) ref : classType {
return this.classArray[i];
}
// Define an implicit iterator for the class
// to yield values from the array to a loop
// i.e. for i in objVar do ...
// i.e. ``for i in objVar do ...``
iter these() ref : classType {
for i in this.classDomain do
yield this[i];
}
} // end GenericClass
// Allocate an owned instance of our class
var realList = new owned GenericClass(real, 10);
// We can assign to the member array of the object using the bracket
// notation that we defined.
var realList = new GenericClass(real, 10);
for i in realList.classDomain do realList[i] = i + 1.0;
// We can iterate over the values in our list with the iterator
@ -823,23 +880,25 @@ for i in realList.classDomain do realList[i] = i + 1.0;
for value in realList do write(value, ", ");
writeln();
// Make a copy of realList using the copy constructor.
var copyList = new GenericClass(realList);
// Make a copy of realList using the copy initializer.
var copyList = new owned GenericClass(realList);
for value in copyList do write(value, ", ");
writeln();
// Make a copy of realList and change the type, also using the copy constructor.
var copyNewTypeList = new GenericClass(realList, int);
// Make a copy of realList and change the type, also using the copy initializer.
var copyNewTypeList = new owned GenericClass(realList, int);
for value in copyNewTypeList do write(value, ", ");
writeln();
// Modules
/*
Modules
*/
// Modules are Chapel's way of managing name spaces.
// The files containing these modules do not need to be named after the modules
// (as in Java), but files implicitly name modules.
// For example, this file implicitly names the learnChapelInYMinutes module
// For example, this file implicitly names the ``learnChapelInYMinutes`` module
module OurModule {
@ -870,21 +929,23 @@ module OurModule {
}
} // end OurModule
// Using OurModule also uses all the modules it uses.
// Since OurModule uses Time, we also use Time.
// Using ``OurModule`` also uses all the modules it uses.
// Since ``OurModule`` uses ``Time``, we also use ``Time``.
use OurModule;
// At this point we have not used ChildModule or SiblingModule so
// their symbols (i.e. foo) are not available to us. However, the module
// names are available, and we can explicitly call foo() through them.
// At this point we have not used ``ChildModule`` or ``SiblingModule`` so
// their symbols (i.e. ``foo``) are not available to us. However, the module
// names are available, and we can explicitly call ``foo()`` through them.
SiblingModule.foo();
OurModule.ChildModule.foo();
// Now we use ChildModule, enabling unqualified calls.
// Now we use ``ChildModule``, enabling unqualified calls.
use ChildModule;
foo();
// Parallelism
/*
Parallelism
*/
// In other languages, parallelism is typically done with
// complicated libraries and strange class structure hierarchies.
@ -894,9 +955,9 @@ foo();
// executed.
proc main() {
// A begin statement will spin the body of that statement off
// A ``begin`` statement will spin the body of that statement off
// into one new task.
// A sync statement will ensure that the progress of the main
// A ``sync`` statement will ensure that the progress of the main
// task will not progress until the children have synced back up.
sync {
@ -913,7 +974,7 @@ proc main() {
writeln("fibonacci(",n,") = ", fibonacci(n));
}
// A cobegin statement will spin each statement of the body into one new
// A ``cobegin`` statement will spin each statement of the body into one new
// task. Notice here that the prints from each statement may happen in any
// order.
cobegin {
@ -929,17 +990,17 @@ proc main() {
}
}
// A coforall loop will create a new task for EACH iteration.
// A ``coforall`` loop will create a new task for EACH iteration.
// Again we see that prints happen in any order.
// NOTE: coforall should be used only for creating tasks!
// NOTE: ``coforall`` should be used only for creating tasks!
// Using it to iterating over a structure is very a bad idea!
var num_tasks = 10; // Number of tasks we want
coforall taskID in 1..#num_tasks {
coforall taskID in 1..num_tasks {
writeln("Hello from task# ", taskID);
}
// forall loops are another parallel loop, but only create a smaller number
// of tasks, specifically --dataParTasksPerLocale= number of tasks.
// ``forall`` loops are another parallel loop, but only create a smaller number
// of tasks, specifically ``--dataParTasksPerLocale=`` number of tasks.
forall i in 1..100 {
write(i, ", ");
}
@ -951,10 +1012,10 @@ proc main() {
// (1..3, 4..6, or 7..9) doing that chunk serially, but each task happens
// in parallel. Your results may depend on your machine and configuration
// For both the forall and coforall loops, the execution of the
// For both the ``forall`` and ``coforall`` loops, the execution of the
// parent task will not continue until all the children sync up.
// forall loops are particularly useful for parallel iteration over arrays.
// ``forall`` loops are particularly useful for parallel iteration over arrays.
// Lets run an experiment to see how much faster a parallel loop is
use Time; // Import the Time module to use Timer objects
var timer: Timer;
@ -982,14 +1043,14 @@ proc main() {
// the parallel loop went faster than the serial loop.
// The bracket style loop-expression described
// much earlier implicitly uses a forall loop.
// much earlier implicitly uses a ``forall`` loop.
[val in myBigArray] val = 1 / val; // Parallel operation
// Atomic variables, common to many languages, are ones whose operations
// occur uninterrupted. Multiple threads can therefore modify atomic
// variables and can know that their values are safe.
// Chapel atomic variables can be of type bool, int,
// uint, and real.
// Chapel atomic variables can be of type ``bool``, ``int``,
// ``uint``, and ``real``.
var uranium: atomic int;
uranium.write(238); // atomically write a variable
writeln(uranium.read()); // atomically read a variable
@ -1003,7 +1064,7 @@ proc main() {
writeln("uranium was ", was, " but is now ", replaceWith);
var isEqualTo = 235;
if uranium.compareExchange(isEqualTo, replaceWith) {
if uranium.compareAndSwap(isEqualTo, replaceWith) {
writeln("uranium was equal to ", isEqualTo,
" so replaced value with ", replaceWith);
} else {
@ -1025,7 +1086,7 @@ proc main() {
}
}
// sync variables have two states: empty and full.
// ``sync`` variables have two states: empty and full.
// If you read an empty variable or write a full variable, you are waited
// until the variable is full or empty again.
var someSyncVar$: sync int; // varName$ is a convention not a law.
@ -1043,9 +1104,8 @@ proc main() {
}
}
// single vars can only be written once. A read on an unwritten single
// results in a wait, but when the variable has a value it can be read
// indefinitely.
// ``single`` vars can only be written once. A read on an unwritten ``single``
// results in a wait, but when the variable has a value it can be read indefinitely.
var someSingleVar$: single int; // varName$ is a convention not a law.
sync {
begin { // Reader task
@ -1063,7 +1123,7 @@ proc main() {
}
}
// Here's an example using atomics and a sync variable to create a
// Here's an example using atomics and a ``sync`` variable to create a
// count-down mutex (also known as a multiplexer).
var count: atomic int; // our counter
var lock$: sync bool; // the mutex lock
@ -1074,7 +1134,7 @@ proc main() {
// (full:unlocked / empty:locked)
// Also, writeXF() fills (F) the sync var regardless of its state (X)
coforall task in 1..#5 { // Generate tasks
coforall task in 1..5 { // Generate tasks
// Create a barrier
do {
lock$; // Read lock$ (wait)
@ -1091,7 +1151,7 @@ proc main() {
lock$.writeXF(true); // Set lock$ to full (signal)
}
// We can define the operations + * & | ^ && || min max minloc maxloc
// We can define the operations ``+ * & | ^ && || min max minloc maxloc``
// over an entire array using scans and reductions.
// Reductions apply the operation over the entire array and
// result in a scalar value.
@ -1099,7 +1159,7 @@ proc main() {
var sumOfValues = + reduce listOfValues;
var maxValue = max reduce listOfValues; // 'max' give just max value
// maxloc gives max value and index of the max value.
// ``maxloc`` gives max value and index of the max value.
// Note: We have to zip the array and domain together with the zip iterator.
var (theMaxValue, idxOfMax) = maxloc reduce zip(listOfValues,
listOfValues.domain);
@ -1108,7 +1168,7 @@ proc main() {
// Scans apply the operation incrementally and return an array with the
// values of the operation at that index as it progressed through the
// array from array.domain.low to array.domain.high.
// array from ``array.domain.low`` to ``array.domain.high``.
var runningSumOfValues = + scan listOfValues;
var maxScan = max scan listOfValues;
writeln(runningSumOfValues);