Execute work in an isolated parallel domain
Execute work in an isolated parallel domain
Section titled “Execute work in an isolated parallel domain”Canonical source:
protos/examples/concurrency/parallel-execution.protosat locked revisione99b712ecf658a527b1fe82c8beba2c1286d8dc9.
This executable example is rendered from the exact Protos source consumed by the website. Its program body is copied without modification.
/* * THE LICENSED WORK IS PROVIDED UNDER THE TERMS OF THE ADAPTIVE PUBLIC LICENSE * ("LICENSE") AS FIRST COMPLETED BY: Guillermo Adrián Molina. ANY USE, PUBLIC * DISPLAY, PUBLIC PERFORMANCE, REPRODUCTION OR DISTRIBUTION OF, OR PREPARATION OF * DERIVATIVE WORKS BASED ON, THE LICENSED WORK CONSTITUTES RECIPIENT'S ACCEPTANCE * OF THIS LICENSE AND ITS TERMS, WHETHER OR NOT SUCH RECIPIENT READS THE TERMS OF * THE LICENSE. "LICENSED WORK" AND "RECIPIENT" ARE DEFINED IN THE LICENSE. A COPY * OF THE LICENSE IS LOCATED IN THE TEXT FILE ENTITLED "LICENSE.TXT" ACCOMPANYING * THE CONTENTS OF THIS FILE. IF A COPY OF THE LICENSE DOES NOT ACCOMPANY THIS * FILE, A COPY OF THE LICENSE MAY ALSO BE OBTAINED AT THE FOLLOWING WEB SITE: * https://github.com/guillermomolina/protos * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for * the specific language governing rights and limitations under the License. */
// Isolated parallel execution: closure.parallel() runs the computation in a// fresh isolated P domain, with no implicit access to the caller's mutable// lexical state. Inputs cross the boundary explicitly, and the result is// observed through an ordinary Future.
// The projected closure has no lexical edge back to the caller, so data is// passed as an argument rather than captured from the surrounding source.multiplier: 6
scale: (value, factor) => { value * factor}
// parallel(...) returns a Future in the caller's execution domain; value()// observes it. Changing `multiplier` after this point cannot affect the// already-snapshotted P input.print(scale.parallel(7, multiplier).value())
// The std:collections/Array parallel algorithms are Standard Library// conveniences composed from the same isolation model (closure.parallel plus// Future.all). Workers may run in any physical order, but every operation below// is deterministic across machines and schedulers. Trailing arguments after the// worker are passed to it explicitly, because workers cannot capture caller// state.Arrays: import("std:collections/Array")
source: Array(3, 1, 4, 1, 5, 9, 2, 6)
// parallelMap preserves logical source order.squares: Arrays.parallelMap(source, (value) => { value * value})print(squares.value())
// parallelFilter preserves source order; the predicate must answer exact// canonical true or false.evens: Arrays.parallelFilter(source, (value) => { value.mod(2) == 0})print(evens.value())
// parallelFindIndex selects the lowest matching logical index, not the// fastest worker, and null means no element matched.firstEven: Arrays.parallelFindIndex(source, (value) => { value.mod(2) == 0})print(firstEven.value())
noMatch: Arrays.parallelFindIndex(source, (value, limit) => { value > limit}, 100)print(noMatch.value())
// parallelReduce combines adjacent pairs round by round, so scheduling does// not choose the parenthesization. Do not assume sequential left-fold// semantics; an empty source reduces to null.sum: Arrays.parallelReduce(source, (a, b) => { a + b})print(sum.value())
emptySum: Arrays.parallelReduce(Array(), (a, b) => { a + b})print(emptySum.value())
// parallelSort is deterministic and stable.sorted: Arrays.parallelSort(source, (a, b) => { a < b})print(sorted.value())