API

@floop

FLoops.@floopMacro
@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, ...
    ...
end

Use @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 ...
end

See the module docstring of FLoops for examples.

source

@reduce

FLoops.@reduceMacro
@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ₙ)
end

should 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
end

This is converted to

acc₁ = init₁
...
accₙ = initₙ
for ...
    # code computing (x₁, x₂, ..., xₙ)
    # code updating (acc₁, acc₂, ..., accₙ) using (x₁, x₂, ..., xₙ)
end

for 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))
source

@init

FLoops.@initMacro
@init begin
    pv₁ = init₁
    ...
    pvₙ = initₙ
end

Initialize private variables pvᵢ with initializer expression initᵢ for each task. This can be used for mutating objects in a data race-free manner.

source

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:

FLoops.assistant

FLoops.assistantFunction
FLoops.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).

source