API
@floop
FLoops.@floop — Macro@floop begin
s₁ = initialization of s₁
s₂ # pre-initialized variable
...
for x in xs, ...
...
end
end@floop begin ... end expects a (possibly empty) series of assignments or variable declaration (as in s₂ above) followed by a for loop.
When there is no induction variables, begin ... end can be omitted:
@floop for x in xs, ...
...
endUse @reduce for parallel execution:
@floop for x in xs, ...
...
@reduce ...
end@floop can also take an executor argument (which should be an instance of executor such as SequentialEx, ThreadedEx and DistributedEx) or a nothing (indicating an appropriate parallel executor):
@floop executor for x in xs, ...
...
@reduce ...
endSee the module docstring of FLoops for examples.
@reduce
FLoops.@reduce — Macro@reduce() do (acc₁ [= init₁]; x₁), ..., (accₙ [= initₙ]; xₙ)
...
end
@reduce(acc₁ ⊗₁= x₁, ..., accₙ ⊗ₙ= xₙ)
@reduce(acc₁ .⊗₁= x₁, ..., accₙ .⊗ₙ= xₙ)
@reduce(acc₁ = ⊗₁(init₁, x₁), ..., accₙ = ⊗ₙ(initₙ, xₙ))
@reduce(acc₁ .= (⊗₁).(init₁, x₁), ..., accₙ = (⊗ₙ).(initₙ, xₙ))Declare how accumulators are updated in the sequential basecase and how the resulting accumulators from two basecases are combined.
The arguments accᵢ and xᵢ must be symbols except for xᵢ of the last three forms in which an expression can be used at xᵢ.
In the first form,
function ((acc₁, acc₂, ..., accₙ), (x₁, x₂, ..., xₙ))
... # body of the `do` block
return (acc₁, acc₂, ..., accₙ)
endshould be an associative function.
In the last three forms, every binary operation ⊗ᵢ should be an associative function.
If initᵢ is specified, the tuple (init₁, init₂, ..., initₙ) should be the identify of the related associative function. accᵢ = initᵢ is evaluated for each basecase (each Task) in the beginning.
Consider a loop with the following form
@floop for ...
# code computing (x₁, x₂, ..., xₙ)
@reduce() do (acc₁ = init₁; x₁), ..., (accₙ = initₙ; xₙ)
# code updating (acc₁, acc₂, ..., accₙ) using (x₁, x₂, ..., xₙ)
end
endThis is converted to
acc₁ = init₁
...
accₙ = initₙ
for ...
# code computing (x₁, x₂, ..., xₙ)
# code updating (acc₁, acc₂, ..., accₙ) using (x₁, x₂, ..., xₙ)
endfor computing (acc₁, acc₂, ..., accₙ) of each basecase. The accumulators accᵢ of two basecases are combined using "code updating (acc₁, acc₂, ..., accₙ) using (x₁, x₂, ..., xₙ)" where (x₁, x₂, ..., xₙ) are replaced with (acc₁, acc₂, ..., accₙ) of the next basecase. Note that "code computing (x₁, x₂, ..., xₙ)" is not used for combining the basecases.
Examples
@reduce() do (vmax=-Inf; v), (imax=0; i)
if isless(vmax, v)
vmax = v
imax = i
end
end
@reduce(s += y, p *= y)
@reduce(xs = append!!(EmptyVector(), x), ys = append!!(EmptyVector(), y))@init
FLoops.@init — Macro@init begin
pv₁ = init₁
...
pvₙ = initₙ
endInitialize private variables pvᵢ with initializer expression initᵢ for each task. This can be used for mutating objects in a data race-free manner.
SequentialEx, ThreadedEx and DistributedEx executors
An executor controls how a given @floop is executed. FLoops.jl re-exports SequentialEx, ThreadedEx and DistributedEx executors from Transducers.jl.
See also:
@flooptutorials on executors- Executor section in Transducers.jl's glossary.
Transducers.SequentialExTransducers.ThreadedExTransducers.DistributedEx- How is a parallel
@floopexecuted? What is the scheduling strategy?
FLoops.assistant
FLoops.assistant — FunctionFLoops.assistant(mode::Symbol)
FLoops.assistant(enable::Bool)Set assistant mode; i.e., what to do when FLoops.jl finds a problematic usage pattern.
Assistant modes:
:ignore: do nothing:warn: print warning once:warn_always: print warning always:error: throw an error
FLoops.assistant(false) is equivalent to FLoops.assistant(:ignore) and FLoops.assistant(true) is equivalent to FLoops.assistant(:warn).